1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "docxattributeoutput.hxx"
22 #include "docxhelper.hxx"
23 #include "docxsdrexport.hxx"
24 #include "docxexportfilter.hxx"
25 #include "docxfootnotes.hxx"
26 #include "writerwordglue.hxx"
28 #include <fmtcntnt.hxx>
30 #include <fchrfmt.hxx>
31 #include <tgrditem.hxx>
32 #include <fmtruby.hxx>
33 #include <fmtanchr.hxx>
34 #include <breakit.hxx>
35 #include <redline.hxx>
36 #include <unocoll.hxx>
37 #include <unoframe.hxx>
38 #include <textboxhelper.hxx>
39 #include <rdfhelper.hxx>
42 #include <comphelper/processfactory.hxx>
43 #include <comphelper/random.hxx>
44 #include <comphelper/string.hxx>
45 #include <comphelper/flagguard.hxx>
46 #include <comphelper/sequence.hxx>
47 #include <oox/token/namespaces.hxx>
48 #include <oox/token/tokens.hxx>
49 #include <oox/export/utils.hxx>
50 #include <oox/mathml/export.hxx>
51 #include <oox/drawingml/drawingmltypes.hxx>
52 #include <oox/token/relationship.hxx>
53 #include <oox/export/vmlexport.hxx>
54 #include <oox/ole/olehelper.hxx>
56 #include <editeng/autokernitem.hxx>
57 #include <editeng/unoprnms.hxx>
58 #include <editeng/fontitem.hxx>
59 #include <editeng/tstpitem.hxx>
60 #include <editeng/spltitem.hxx>
61 #include <editeng/widwitem.hxx>
62 #include <editeng/shaditem.hxx>
63 #include <editeng/brushitem.hxx>
64 #include <editeng/postitem.hxx>
65 #include <editeng/wghtitem.hxx>
66 #include <editeng/kernitem.hxx>
67 #include <editeng/crossedoutitem.hxx>
68 #include <editeng/cmapitem.hxx>
69 #include <editeng/udlnitem.hxx>
70 #include <editeng/langitem.hxx>
71 #include <editeng/lspcitem.hxx>
72 #include <editeng/escapementitem.hxx>
73 #include <editeng/fhgtitem.hxx>
74 #include <editeng/colritem.hxx>
75 #include <editeng/hyphenzoneitem.hxx>
76 #include <editeng/ulspitem.hxx>
77 #include <editeng/contouritem.hxx>
78 #include <editeng/shdditem.hxx>
79 #include <editeng/emphasismarkitem.hxx>
80 #include <editeng/twolinesitem.hxx>
81 #include <editeng/charscaleitem.hxx>
82 #include <editeng/charrotateitem.hxx>
83 #include <editeng/charreliefitem.hxx>
84 #include <editeng/paravertalignitem.hxx>
85 #include <editeng/pgrditem.hxx>
86 #include <editeng/frmdiritem.hxx>
87 #include <editeng/blinkitem.hxx>
88 #include <editeng/charhiddenitem.hxx>
89 #include <editeng/editobj.hxx>
90 #include <editeng/keepitem.hxx>
91 #include <editeng/borderline.hxx>
92 #include <svx/xdef.hxx>
93 #include <svx/xfillit0.hxx>
94 #include <svx/xflclit.hxx>
95 #include <svx/xflgrit.hxx>
96 #include <svx/xlineit0.hxx>
97 #include <svx/xlnclit.hxx>
98 #include <svx/xlnwtit.hxx>
99 #include <svx/svdouno.hxx>
100 #include <svx/unobrushitemhelper.hxx>
101 #include <svl/grabbagitem.hxx>
102 #include <sfx2/sfxbasemodel.hxx>
103 #include <tools/datetimeutils.hxx>
104 #include <tools/UnitConversion.hxx>
105 #include <svl/whiter.hxx>
106 #include <rtl/tencinfo.h>
107 #include <sal/log.hxx>
108 #include <sot/exchange.hxx>
110 #include <docufld.hxx>
111 #include <authfld.hxx>
112 #include <flddropdown.hxx>
113 #include <fmtclds.hxx>
114 #include <fmtinfmt.hxx>
115 #include <fmtrowsplt.hxx>
116 #include <fmtline.hxx>
117 #include <ftninfo.hxx>
118 #include <htmltbl.hxx>
119 #include <lineinfo.hxx>
123 #include <pagedesc.hxx>
124 #include <paratr.hxx>
125 #include <swmodule.hxx>
126 #include <swtable.hxx>
127 #include <txtftn.hxx>
128 #include <fmtautofmt.hxx>
130 #include <docary.hxx>
131 #include <fmtclbl.hxx>
132 #include <IDocumentSettingAccess.hxx>
133 #include <IDocumentRedlineAccess.hxx>
134 #include <grfatr.hxx>
135 #include <frmatr.hxx>
136 #include <txtatr.hxx>
137 #include <frameformats.hxx>
139 #include <osl/file.hxx>
141 #include <vcl/embeddedfontshelper.hxx>
143 #include <com/sun/star/i18n/ScriptType.hpp>
144 #include <com/sun/star/i18n/XBreakIterator.hpp>
145 #include <com/sun/star/chart2/XChartDocument.hpp>
146 #include <com/sun/star/drawing/ShadingPattern.hpp>
147 #include <com/sun/star/text/GraphicCrop.hpp>
148 #include <com/sun/star/embed/EmbedStates.hpp>
149 #include <com/sun/star/embed/Aspects.hpp>
153 #include <string_view>
155 #include <toolkit/helper/vclunohelper.hxx>
156 #include <unicode/regex.h>
158 using ::editeng::SvxBorderLine
;
161 using namespace docx
;
162 using namespace sax_fastparser
;
163 using namespace nsSwDocInfoSubType
;
164 using namespace sw::util
;
165 using namespace ::com::sun::star
;
166 using namespace ::com::sun::star::drawing
;
168 const sal_Int32 Tag_StartParagraph_1
= 1;
169 const sal_Int32 Tag_StartParagraph_2
= 2;
170 const sal_Int32 Tag_WriteSdtBlock
= 3;
171 const sal_Int32 Tag_StartParagraphProperties
= 4;
172 const sal_Int32 Tag_InitCollectedParagraphProperties
= 5;
173 const sal_Int32 Tag_StartRun_1
= 6;
174 const sal_Int32 Tag_StartRun_2
= 7;
175 const sal_Int32 Tag_StartRun_3
= 8;
176 const sal_Int32 Tag_EndRun_1
= 9;
177 const sal_Int32 Tag_EndRun_2
= 10;
178 const sal_Int32 Tag_StartRunProperties
= 11;
179 const sal_Int32 Tag_InitCollectedRunProperties
= 12;
180 //static const sal_Int32 Tag_Redline_1 = 13;
181 const sal_Int32 Tag_Redline_2
= 14;
182 const sal_Int32 Tag_TableDefinition
= 15;
183 const sal_Int32 Tag_OutputFlyFrame
= 16;
184 const sal_Int32 Tag_StartSection
= 17;
188 class FFDataWriterHelper
190 ::sax_fastparser::FSHelperPtr m_pSerializer
;
191 void writeCommonStart( const OUString
& rName
,
192 const OUString
& rEntryMacro
,
193 const OUString
& rExitMacro
,
194 const OUString
& rHelp
,
195 const OUString
& rHint
)
197 m_pSerializer
->startElementNS(XML_w
, XML_ffData
);
198 m_pSerializer
->singleElementNS(XML_w
, XML_name
, FSNS(XML_w
, XML_val
), rName
);
199 m_pSerializer
->singleElementNS(XML_w
, XML_enabled
);
200 m_pSerializer
->singleElementNS(XML_w
, XML_calcOnExit
, FSNS(XML_w
, XML_val
), "0");
202 if ( !rEntryMacro
.isEmpty() )
203 m_pSerializer
->singleElementNS( XML_w
, XML_entryMacro
,
204 FSNS(XML_w
, XML_val
), rEntryMacro
);
206 if ( !rExitMacro
.isEmpty() )
207 m_pSerializer
->singleElementNS(XML_w
, XML_exitMacro
, FSNS(XML_w
, XML_val
), rExitMacro
);
209 if ( !rHelp
.isEmpty() )
210 m_pSerializer
->singleElementNS( XML_w
, XML_helpText
,
211 FSNS(XML_w
, XML_type
), "text",
212 FSNS(XML_w
, XML_val
), rHelp
);
214 if ( !rHint
.isEmpty() )
215 m_pSerializer
->singleElementNS( XML_w
, XML_statusText
,
216 FSNS(XML_w
, XML_type
), "text",
217 FSNS(XML_w
, XML_val
), rHint
);
222 m_pSerializer
->endElementNS( XML_w
, XML_ffData
);
225 explicit FFDataWriterHelper( ::sax_fastparser::FSHelperPtr rSerializer
) : m_pSerializer(std::move( rSerializer
)){}
226 void WriteFormCheckbox( const OUString
& rName
,
227 const OUString
& rEntryMacro
,
228 const OUString
& rExitMacro
,
229 const OUString
& rHelp
,
230 const OUString
& rHint
,
233 writeCommonStart( rName
, rEntryMacro
, rExitMacro
, rHelp
, rHint
);
234 // Checkbox specific bits
235 m_pSerializer
->startElementNS(XML_w
, XML_checkBox
);
236 // currently hardcoding autosize
237 // #TODO check if this defaulted
238 m_pSerializer
->startElementNS(XML_w
, XML_sizeAuto
);
239 m_pSerializer
->endElementNS( XML_w
, XML_sizeAuto
);
241 m_pSerializer
->singleElementNS(XML_w
, XML_checked
);
242 m_pSerializer
->endElementNS( XML_w
, XML_checkBox
);
246 void WriteFormText( const OUString
& rName
,
247 const OUString
& rEntryMacro
,
248 const OUString
& rExitMacro
,
249 const OUString
& rHelp
,
250 const OUString
& rHint
,
251 const OUString
& rType
,
252 const OUString
& rDefaultText
,
253 sal_uInt16 nMaxLength
,
254 const OUString
& rFormat
)
256 writeCommonStart( rName
, rEntryMacro
, rExitMacro
, rHelp
, rHint
);
258 m_pSerializer
->startElementNS(XML_w
, XML_textInput
);
259 if ( !rType
.isEmpty() )
260 m_pSerializer
->singleElementNS(XML_w
, XML_type
, FSNS(XML_w
, XML_val
), rType
);
261 if ( !rDefaultText
.isEmpty() )
262 m_pSerializer
->singleElementNS(XML_w
, XML_default
, FSNS(XML_w
, XML_val
), rDefaultText
);
264 m_pSerializer
->singleElementNS( XML_w
, XML_maxLength
,
265 FSNS(XML_w
, XML_val
), OString::number(nMaxLength
) );
266 if ( !rFormat
.isEmpty() )
267 m_pSerializer
->singleElementNS(XML_w
, XML_format
, FSNS(XML_w
, XML_val
), rFormat
);
268 m_pSerializer
->endElementNS( XML_w
, XML_textInput
);
274 class FieldMarkParamsHelper
276 const sw::mark::IFieldmark
& mrFieldmark
;
278 explicit FieldMarkParamsHelper( const sw::mark::IFieldmark
& rFieldmark
) : mrFieldmark( rFieldmark
) {}
279 OUString
const & getName() const { return mrFieldmark
.GetName(); }
280 template < typename T
>
281 bool extractParam( const OUString
& rKey
, T
& rResult
)
283 bool bResult
= false;
284 if ( mrFieldmark
.GetParameters() )
286 sw::mark::IFieldmark::parameter_map_t::const_iterator it
= mrFieldmark
.GetParameters()->find( rKey
);
287 if ( it
!= mrFieldmark
.GetParameters()->end() )
288 bResult
= ( it
->second
>>= rResult
);
296 void DocxAttributeOutput::RTLAndCJKState( bool bIsRTL
, sal_uInt16
/*nScript*/ )
299 m_pSerializer
->singleElementNS(XML_w
, XML_rtl
, FSNS(XML_w
, XML_val
), "true");
302 /// Are multiple paragraphs disallowed inside this type of SDT?
303 static bool lcl_isOnelinerSdt(const OUString
& rName
)
305 return rName
== "Title" || rName
== "Subtitle" || rName
== "Company";
308 // write a floating table directly to docx without the surrounding frame
309 void DocxAttributeOutput::WriteFloatingTable(ww8::Frame
const* pParentFrame
)
311 const SwFrameFormat
& rFrameFormat
= pParentFrame
->GetFrameFormat();
312 m_aFloatingTablesOfParagraph
.insert(&rFrameFormat
);
313 const SwNodeIndex
* pNodeIndex
= rFrameFormat
.GetContent().GetContentIdx();
315 sal_uLong nStt
= pNodeIndex
? pNodeIndex
->GetIndex() + 1 : 0;
316 sal_uLong nEnd
= pNodeIndex
? pNodeIndex
->GetNode().EndOfSectionIndex() : 0;
318 //Save data here and restore when out of scope
319 ExportDataSaveRestore
aDataGuard(GetExport(), nStt
, nEnd
, pParentFrame
);
321 // set a floatingTableFrame AND unset parent frame,
322 // otherwise exporter thinks we are still in a frame
323 m_rExport
.SetFloatingTableFrame(pParentFrame
);
324 m_rExport
.m_pParentFrame
= nullptr;
326 GetExport().WriteText();
328 m_rExport
.SetFloatingTableFrame(nullptr);
331 static void checkAndWriteFloatingTables(DocxAttributeOutput
& rDocxAttributeOutput
)
333 const auto& rExport
= rDocxAttributeOutput
.GetExport();
334 // iterate though all SpzFrameFormats and check whether they are anchored to the current text node
335 for( sal_uInt16 nCnt
= rExport
.m_rDoc
.GetSpzFrameFormats()->size(); nCnt
; )
337 const SwFrameFormat
* pFrameFormat
= (*rExport
.m_rDoc
.GetSpzFrameFormats())[ --nCnt
];
338 const SwFormatAnchor
& rAnchor
= pFrameFormat
->GetAnchor();
339 const SwPosition
* pPosition
= rAnchor
.GetContentAnchor();
341 if (!pPosition
|| ! rExport
.m_pCurPam
->GetNode().GetTextNode())
344 if (pPosition
->nNode
!= rExport
.m_pCurPam
->GetNode().GetTextNode()->GetIndex())
347 const SwNodeIndex
* pStartNode
= pFrameFormat
->GetContent().GetContentIdx();
351 SwNodeIndex aStartNode
= *pStartNode
;
353 // go to the next node (actual content)
356 // this has to be a table
357 if (!aStartNode
.GetNode().IsTableNode())
360 // go to the end of the table
361 sal_uLong aEndIndex
= aStartNode
.GetNode().EndOfSectionIndex();
364 // this has to be the end of the content
365 if (aEndIndex
!= pFrameFormat
->GetContent().GetContentIdx()->GetNode().EndOfSectionIndex())
368 // check for a grabBag and "TablePosition" attribute -> then we can export the table directly
369 SwTableNode
* pTableNode
= aStartNode
.GetNode().GetTableNode();
370 SwTable
& rTable
= pTableNode
->GetTable();
371 SwFrameFormat
* pTableFormat
= rTable
.GetFrameFormat();
372 const SfxGrabBagItem
* pTableGrabBag
= pTableFormat
->GetAttrSet().GetItem
<SfxGrabBagItem
>(RES_FRMATR_GRABBAG
);
373 std::map
<OUString
, css::uno::Any
> aTableGrabBag
= pTableGrabBag
->GetGrabBag();
375 if (aTableGrabBag
.find("TablePosition") == aTableGrabBag
.end())
378 // write table to docx
379 ww8::Frame
aFrame(*pFrameFormat
,*pPosition
);
380 rDocxAttributeOutput
.WriteFloatingTable(&aFrame
);
384 void DocxAttributeOutput::StartParagraph( ww8::WW8TableNodeInfo::Pointer_t pTextNodeInfo
)
386 // look ahead for floating tables that were put into a frame during import
387 // floating tables in shapes are not supported: exclude this case
388 if (!pTextNodeInfo
&& !m_rExport
.SdrExporter().IsDMLAndVMLDrawingOpen())
390 checkAndWriteFloatingTables(*this);
393 if ( m_nColBreakStatus
== COLBRK_POSTPONE
)
394 m_nColBreakStatus
= COLBRK_WRITE
;
396 // Output table/table row/table cell starts if needed
400 if ( m_tableReference
->m_nTableDepth
> 0 && !m_tableReference
->m_bTableCellOpen
)
402 ww8::WW8TableNodeInfoInner::Pointer_t
pDeepInner( pTextNodeInfo
->getInnerForDepth( m_tableReference
->m_nTableDepth
) );
403 if ( pDeepInner
->getCell() == 0 )
404 StartTableRow( pDeepInner
);
406 const sal_uInt32 nCell
= pDeepInner
->getCell();
407 const sal_uInt32 nRow
= pDeepInner
->getRow();
409 SyncNodelessCells(pDeepInner
, nCell
, nRow
);
410 StartTableCell(pDeepInner
, nCell
, nRow
);
413 sal_uInt32 nRow
= pTextNodeInfo
->getRow();
414 sal_uInt32 nCell
= pTextNodeInfo
->getCell();
417 // Do we have to start the table?
418 // [If we are at the right depth already, it means that we
419 // continue the table cell]
420 sal_uInt32 nCurrentDepth
= pTextNodeInfo
->getDepth();
422 if ( nCurrentDepth
> m_tableReference
->m_nTableDepth
)
424 // Start all the tables that begin here
425 for ( sal_uInt32 nDepth
= m_tableReference
->m_nTableDepth
+ 1; nDepth
<= nCurrentDepth
; ++nDepth
)
427 ww8::WW8TableNodeInfoInner::Pointer_t
pInner( pTextNodeInfo
->getInnerForDepth( nDepth
) );
429 StartTable( pInner
);
430 StartTableRow( pInner
);
432 StartTableCell(pInner
, 0, nDepth
== nCurrentDepth
? nRow
: 0);
435 m_tableReference
->m_nTableDepth
= nCurrentDepth
;
440 // Look up the "sdt end before this paragraph" property early, when it
441 // would normally arrive, it would be too late (would be after the
442 // paragraph start has been written).
443 bool bEndParaSdt
= false;
444 if (m_bStartedParaSdt
)
446 SwTextNode
* pTextNode
= m_rExport
.m_pCurPam
->GetNode().GetTextNode();
447 if (pTextNode
&& pTextNode
->GetpSwAttrSet())
449 const SfxItemSet
* pSet
= pTextNode
->GetpSwAttrSet();
450 if (const SfxPoolItem
* pItem
= pSet
->GetItem(RES_PARATR_GRABBAG
))
452 const SfxGrabBagItem
& rParaGrabBag
= static_cast<const SfxGrabBagItem
&>(*pItem
);
453 const std::map
<OUString
, css::uno::Any
>& rMap
= rParaGrabBag
.GetGrabBag();
454 bEndParaSdt
= m_bStartedParaSdt
&& rMap
.find("ParaSdtEndBefore") != rMap
.end();
458 // TODO also avoid multiline paragraphs in those SDT types for shape text
459 bool bOneliner
= m_bStartedParaSdt
&& !m_rExport
.SdrExporter().IsDMLAndVMLDrawingOpen() && lcl_isOnelinerSdt(m_aStartedParagraphSdtPrAlias
);
460 if (bEndParaSdt
|| (m_bStartedParaSdt
&& m_bHadSectPr
) || bOneliner
)
462 // This is the common case: "close sdt before the current paragraph" was requested by the next paragraph.
464 m_bStartedParaSdt
= false;
465 m_aStartedParagraphSdtPrAlias
.clear();
467 m_bHadSectPr
= false;
469 // this mark is used to be able to enclose the paragraph inside a sdr tag.
470 // We will only know if we have to do that later.
471 m_pSerializer
->mark(Tag_StartParagraph_1
);
473 m_pSerializer
->startElementNS(XML_w
, XML_p
);
475 // postpone the output of the run (we get it before the paragraph
476 // properties, but must write it after them)
477 m_pSerializer
->mark(Tag_StartParagraph_2
);
479 // no section break in this paragraph yet; can be set in SectionBreak()
480 m_pSectionInfo
.reset();
482 m_bParagraphOpened
= true;
483 m_bIsFirstParagraph
= false;
486 static OString
convertToOOXMLVertOrient(sal_Int16 nOrient
)
490 case text::VertOrientation::CENTER
:
491 case text::VertOrientation::LINE_CENTER
:
493 case text::VertOrientation::BOTTOM
:
495 case text::VertOrientation::LINE_BOTTOM
:
497 case text::VertOrientation::TOP
:
499 case text::VertOrientation::LINE_TOP
:
506 static OString
convertToOOXMLHoriOrient(sal_Int16 nOrient
, bool bIsPosToggle
)
510 case text::HoriOrientation::LEFT
:
511 return bIsPosToggle
? "inside" : "left";
512 case text::HoriOrientation::INSIDE
:
514 case text::HoriOrientation::RIGHT
:
515 return bIsPosToggle
? "outside" : "right";
516 case text::HoriOrientation::OUTSIDE
:
518 case text::HoriOrientation::CENTER
:
519 case text::HoriOrientation::FULL
:
526 static OString
convertToOOXMLVertOrientRel(sal_Int16 nOrientRel
)
530 case text::RelOrientation::PAGE_PRINT_AREA
:
532 case text::RelOrientation::PAGE_FRAME
:
534 case text::RelOrientation::FRAME
:
535 case text::RelOrientation::TEXT_LINE
:
541 static OString
convertToOOXMLHoriOrientRel(sal_Int16 nOrientRel
)
545 case text::RelOrientation::PAGE_PRINT_AREA
:
547 case text::RelOrientation::PAGE_FRAME
:
549 case text::RelOrientation::CHAR
:
550 case text::RelOrientation::PAGE_RIGHT
:
551 case text::RelOrientation::FRAME
:
557 static void lcl_deleteAndResetTheLists( rtl::Reference
<sax_fastparser::FastAttributeList
>& pSdtPrTokenChildren
, rtl::Reference
<sax_fastparser::FastAttributeList
>& pSdtPrDataBindingAttrs
, OUString
& rSdtPrAlias
)
559 if( pSdtPrTokenChildren
.is() )
560 pSdtPrTokenChildren
.clear();
561 if( pSdtPrDataBindingAttrs
.is() )
562 pSdtPrDataBindingAttrs
.clear();
563 if (!rSdtPrAlias
.isEmpty())
567 void DocxAttributeOutput::PopulateFrameProperties(const SwFrameFormat
* pFrameFormat
, const Size
& rSize
)
569 sax_fastparser::FastAttributeList
* attrList
= FastSerializerHelper::createAttrList();
571 awt::Point
aPos(pFrameFormat
->GetHoriOrient().GetPos(), pFrameFormat
->GetVertOrient().GetPos());
573 attrList
->add( FSNS( XML_w
, XML_w
), OString::number(rSize
.Width()));
574 attrList
->add( FSNS( XML_w
, XML_h
), OString::number(rSize
.Height()));
576 attrList
->add( FSNS( XML_w
, XML_x
), OString::number(aPos
.X
));
577 attrList
->add( FSNS( XML_w
, XML_y
), OString::number(aPos
.Y
));
579 sal_Int16 nLeft
= pFrameFormat
->GetLRSpace().GetLeft();
580 sal_Int16 nRight
= pFrameFormat
->GetLRSpace().GetRight();
581 sal_Int16 nUpper
= pFrameFormat
->GetULSpace().GetUpper();
582 sal_Int16 nLower
= pFrameFormat
->GetULSpace().GetLower();
584 attrList
->add(FSNS(XML_w
, XML_hSpace
), OString::number((nLeft
+ nRight
) / 2));
585 attrList
->add(FSNS(XML_w
, XML_vSpace
), OString::number((nUpper
+ nLower
) / 2));
587 OString relativeFromH
= convertToOOXMLHoriOrientRel( pFrameFormat
->GetHoriOrient().GetRelationOrient() );
588 OString relativeFromV
= convertToOOXMLVertOrientRel( pFrameFormat
->GetVertOrient().GetRelationOrient() );
590 switch (pFrameFormat
->GetSurround().GetValue())
592 case css::text::WrapTextMode_NONE
:
593 attrList
->add( FSNS( XML_w
, XML_wrap
), "notBeside");
595 case css::text::WrapTextMode_DYNAMIC
:
596 attrList
->add(FSNS(XML_w
, XML_wrap
), "auto");
598 case css::text::WrapTextMode_PARALLEL
:
600 attrList
->add(FSNS(XML_w
, XML_wrap
), "around");
603 attrList
->add( FSNS( XML_w
, XML_vAnchor
), relativeFromV
);
604 attrList
->add( FSNS( XML_w
, XML_hAnchor
), relativeFromH
);
605 attrList
->add( FSNS( XML_w
, XML_hRule
), "exact");
607 sax_fastparser::XFastAttributeListRef
xAttrList(attrList
);
608 m_pSerializer
->singleElementNS( XML_w
, XML_framePr
, xAttrList
);
611 bool DocxAttributeOutput::TextBoxIsFramePr(const SwFrameFormat
& rFrameFormat
)
613 uno::Reference
< drawing::XShape
> xShape
;
614 const SdrObject
* pSdrObj
= rFrameFormat
.FindRealSdrObject();
616 xShape
.set(const_cast<SdrObject
*>(pSdrObj
)->getUnoShape(), uno::UNO_QUERY
);
617 uno::Reference
< beans::XPropertySet
> xPropertySet(xShape
, uno::UNO_QUERY
);
618 uno::Reference
< beans::XPropertySetInfo
> xPropSetInfo
;
619 if (xPropertySet
.is())
620 xPropSetInfo
= xPropertySet
->getPropertySetInfo();
621 uno::Any aFrameProperties
;
622 if (xPropSetInfo
.is() && xPropSetInfo
->hasPropertyByName("FrameInteropGrabBag"))
624 uno::Sequence
< beans::PropertyValue
> propList
;
625 xPropertySet
->getPropertyValue("FrameInteropGrabBag") >>= propList
;
626 auto pProp
= std::find_if(propList
.begin(), propList
.end(),
627 [](const beans::PropertyValue
& rProp
) { return rProp
.Name
== "ParaFrameProperties"; });
628 if (pProp
!= propList
.end())
629 aFrameProperties
= pProp
->Value
;
631 bool bFrameProperties
= false;
632 aFrameProperties
>>= bFrameProperties
;
633 return bFrameProperties
;
636 void DocxAttributeOutput::EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t pTextNodeInfoInner
)
638 // write the paragraph properties + the run, already in the correct order
639 m_pSerializer
->mergeTopMarks(Tag_StartParagraph_2
);
640 std::vector
< std::shared_ptr
<ww8::Frame
> > aFramePrTextbox
;
641 // Write the anchored frame if any
642 // Word can't handle nested text boxes, so write them on the same level.
644 if( m_nTextFrameLevel
== 1 && !m_rExport
.SdrExporter().IsDMLAndVMLDrawingOpen() )
646 comphelper::FlagRestorationGuard
aStartedParaSdtGuard(m_bStartedParaSdt
, false);
648 assert(!m_pPostponedCustomShape
);
649 m_pPostponedCustomShape
.reset(new std::vector
<PostponedDrawing
>);
650 for (size_t nIndex
= 0; nIndex
< m_aFramesOfParagraph
.size(); ++nIndex
)
652 m_bParagraphFrameOpen
= true;
653 ww8::Frame aFrame
= m_aFramesOfParagraph
[nIndex
];
654 const SwFrameFormat
& rFrameFormat
= aFrame
.GetFrameFormat();
656 if (!TextBoxIsFramePr(rFrameFormat
) || m_bWritingHeaderFooter
)
658 if (m_bStartedCharSdt
)
660 // Run-level SDT still open? Close it before AlternateContent.
662 m_bStartedCharSdt
= false;
664 m_pSerializer
->startElementNS(XML_w
, XML_r
);
665 m_pSerializer
->startElementNS(XML_mc
, XML_AlternateContent
);
666 m_pSerializer
->startElementNS(XML_mc
, XML_Choice
, XML_Requires
, "wps");
668 This is to avoid AlternateContent within another AlternateContent.
669 So when Choice is Open, only write the DML Drawing instead of both DML
670 and VML Drawing in another AlternateContent.
672 SetAlternateContentChoiceOpen( true );
673 /** Save the table info's before writing the shape
674 as there might be a new table that might get
675 spawned from within the VML & DML block and alter
678 ww8::WW8TableInfo::Pointer_t pOldTableInfo
= m_rExport
.m_pTableInfo
;
679 //Reset the table infos after saving.
680 m_rExport
.m_pTableInfo
= std::make_shared
<ww8::WW8TableInfo
>();
683 Save the table reference attributes before calling WriteDMLTextFrame,
684 otherwise the StartParagraph function will use the previous existing
685 table reference attributes since the variable is being shared.
688 DocxTableExportContext
aDMLTableExportContext(*this);
689 m_rExport
.SdrExporter().writeDMLTextFrame(&aFrame
, m_anchorId
++);
691 m_pSerializer
->endElementNS(XML_mc
, XML_Choice
);
692 SetAlternateContentChoiceOpen( false );
694 // Reset table infos, otherwise the depth of the cells will be incorrect,
695 // in case the text frame had table(s) and we try to export the
696 // same table second time.
697 m_rExport
.m_pTableInfo
= std::make_shared
<ww8::WW8TableInfo
>();
698 //reset the tableReference.
700 m_pSerializer
->startElementNS(XML_mc
, XML_Fallback
);
702 DocxTableExportContext
aVMLTableExportContext(*this);
703 m_rExport
.SdrExporter().writeVMLTextFrame(&aFrame
);
705 m_rExport
.m_pTableInfo
= pOldTableInfo
;
707 m_pSerializer
->endElementNS(XML_mc
, XML_Fallback
);
708 m_pSerializer
->endElementNS(XML_mc
, XML_AlternateContent
);
709 m_pSerializer
->endElementNS( XML_w
, XML_r
);
710 m_bParagraphFrameOpen
= false;
714 std::shared_ptr
<ww8::Frame
> pFramePr
= std::make_shared
<ww8::Frame
>(aFrame
);
715 aFramePrTextbox
.push_back(pFramePr
);
718 if (!m_pPostponedCustomShape
->empty())
720 m_pSerializer
->startElementNS(XML_w
, XML_r
);
721 WritePostponedCustomShape();
722 m_pSerializer
->endElementNS( XML_w
, XML_r
);
724 m_pPostponedCustomShape
.reset();
726 m_aFramesOfParagraph
.clear();
728 if (!pTextNodeInfoInner
)
730 // Ending a non-table paragraph, clear floating tables before paragraph.
731 m_aFloatingTablesOfParagraph
.clear();
737 /* If m_nHyperLinkCount > 0 that means hyperlink tag is not yet closed.
738 * This is due to nested hyperlink tags. So close it before end of paragraph.
740 if(m_nHyperLinkCount
> 0)
742 for(sal_Int32 nHyperLinkToClose
= 0; nHyperLinkToClose
< m_nHyperLinkCount
; ++nHyperLinkToClose
)
743 m_pSerializer
->endElementNS( XML_w
, XML_hyperlink
);
744 m_nHyperLinkCount
= 0;
747 if (m_bStartedCharSdt
)
749 // Run-level SDT still open? Close it now.
751 m_bStartedCharSdt
= false;
754 if (m_bPageBreakAfter
)
756 // tdf#128889 Trailing page break
757 SectionBreak(msword::PageBreak
, false);
758 m_bPageBreakAfter
= false;
761 m_pSerializer
->endElementNS( XML_w
, XML_p
);
762 // on export sdt blocks are never nested ATM
763 if( !m_bAnchorLinkedToNode
&& !m_bStartedParaSdt
)
764 WriteSdtBlock( m_nParagraphSdtPrToken
, m_pParagraphSdtPrTokenChildren
, m_pParagraphSdtPrTokenAttributes
, m_pParagraphSdtPrDataBindingAttrs
, m_aParagraphSdtPrAlias
, /*bPara=*/true );
767 //These should be written out to the actual Node and not to the anchor.
768 //Clear them as they will be repopulated when the node is processed.
769 m_nParagraphSdtPrToken
= 0;
770 m_bParagraphSdtHasId
= false;
771 lcl_deleteAndResetTheLists( m_pParagraphSdtPrTokenChildren
, m_pParagraphSdtPrDataBindingAttrs
, m_aParagraphSdtPrAlias
);
774 m_pSerializer
->mark(Tag_StartParagraph_2
);
777 for ( const auto & pFrame
: aFramePrTextbox
)
779 DocxTableExportContext
aTableExportContext(*this);
780 m_pCurrentFrame
= pFrame
.get();
781 m_rExport
.SdrExporter().writeOnlyTextOfFrame(pFrame
.get());
782 m_pCurrentFrame
= nullptr;
785 m_pSerializer
->mergeTopMarks(Tag_StartParagraph_2
, sax_fastparser::MergeMarks::PREPEND
);
787 //sdtcontent is written so Set m_bParagraphHasDrawing to false
788 m_rExport
.SdrExporter().setParagraphHasDrawing(false);
789 m_bRunTextIsOn
= false;
790 m_pSerializer
->mergeTopMarks(Tag_StartParagraph_1
);
792 aFramePrTextbox
.clear();
793 // Check for end of cell, rows, tables here
794 FinishTableRowCell( pTextNodeInfoInner
);
796 if( !m_rExport
.SdrExporter().IsDMLAndVMLDrawingOpen() )
797 m_bParagraphOpened
= false;
799 // Clear bookmarks of the current paragraph
800 m_aBookmarksOfParagraphStart
.clear();
801 m_aBookmarksOfParagraphEnd
.clear();
804 void DocxAttributeOutput::WriteSdtBlock( sal_Int32
& nSdtPrToken
,
805 rtl::Reference
<sax_fastparser::FastAttributeList
>& pSdtPrTokenChildren
,
806 rtl::Reference
<sax_fastparser::FastAttributeList
>& pSdtPrTokenAttributes
,
807 rtl::Reference
<sax_fastparser::FastAttributeList
>& pSdtPrDataBindingAttrs
,
808 OUString
& rSdtPrAlias
,
811 if( nSdtPrToken
<= 0 && !pSdtPrDataBindingAttrs
.is() )
815 m_pSerializer
->mark(Tag_WriteSdtBlock
);
817 m_pSerializer
->startElementNS(XML_w
, XML_sdt
);
819 // output sdt properties
820 m_pSerializer
->startElementNS(XML_w
, XML_sdtPr
);
822 if( nSdtPrToken
> 0 && pSdtPrTokenChildren
.is() )
824 if (!pSdtPrTokenAttributes
.is())
825 m_pSerializer
->startElement(nSdtPrToken
);
828 XFastAttributeListRef
xAttrList(pSdtPrTokenAttributes
.get());
829 pSdtPrTokenAttributes
.clear();
830 m_pSerializer
->startElement(nSdtPrToken
, xAttrList
);
833 if (nSdtPrToken
== FSNS( XML_w
, XML_date
) || nSdtPrToken
== FSNS( XML_w
, XML_docPartObj
) || nSdtPrToken
== FSNS( XML_w
, XML_docPartList
) || nSdtPrToken
== FSNS( XML_w14
, XML_checkbox
)) {
834 const uno::Sequence
<xml::FastAttribute
> aChildren
= pSdtPrTokenChildren
->getFastAttributes();
835 for( const auto& rChild
: aChildren
)
836 m_pSerializer
->singleElement(rChild
.Token
, FSNS(XML_w
, XML_val
), rChild
.Value
);
839 m_pSerializer
->endElement( nSdtPrToken
);
841 else if( (nSdtPrToken
> 0) && nSdtPrToken
!= FSNS( XML_w
, XML_id
) && !(m_bRunTextIsOn
&& m_rExport
.SdrExporter().IsParagraphHasDrawing()))
843 if (!pSdtPrTokenAttributes
.is())
844 m_pSerializer
->singleElement(nSdtPrToken
);
847 XFastAttributeListRef
xAttrList(pSdtPrTokenAttributes
.get());
848 pSdtPrTokenAttributes
.clear();
849 m_pSerializer
->singleElement(nSdtPrToken
, xAttrList
);
853 if( nSdtPrToken
== FSNS( XML_w
, XML_id
) || ( bPara
&& m_bParagraphSdtHasId
) )
854 //Word won't open a document with an empty id tag, we fill it with a random number
855 m_pSerializer
->singleElementNS(XML_w
, XML_id
, FSNS(XML_w
, XML_val
),
856 OString::number(comphelper::rng::uniform_int_distribution(0, std::numeric_limits
<int>::max())));
858 if( pSdtPrDataBindingAttrs
.is() && !m_rExport
.SdrExporter().IsParagraphHasDrawing())
860 XFastAttributeListRef
xAttrList( pSdtPrDataBindingAttrs
.get() );
861 pSdtPrDataBindingAttrs
.clear();
862 m_pSerializer
->singleElementNS(XML_w
, XML_dataBinding
, xAttrList
);
865 if (!rSdtPrAlias
.isEmpty())
866 m_pSerializer
->singleElementNS(XML_w
, XML_alias
, FSNS(XML_w
, XML_val
), rSdtPrAlias
);
868 m_pSerializer
->endElementNS( XML_w
, XML_sdtPr
);
870 // sdt contents start tag
871 m_pSerializer
->startElementNS(XML_w
, XML_sdtContent
);
873 // prepend the tags since the sdt start mark before the paragraph
874 m_pSerializer
->mergeTopMarks(Tag_WriteSdtBlock
, sax_fastparser::MergeMarks::PREPEND
);
876 // write the ending tags after the paragraph
879 m_bStartedParaSdt
= true;
880 if (m_tableReference
->m_bTableCellOpen
)
881 m_tableReference
->m_bTableCellParaSdtOpen
= true;
882 if (m_rExport
.SdrExporter().IsDMLAndVMLDrawingOpen())
883 m_rExport
.SdrExporter().setParagraphSdtOpen(true);
886 // Support multiple runs inside a run-level SDT: don't close the SDT block yet.
887 m_bStartedCharSdt
= true;
891 pSdtPrTokenChildren
.clear();
892 pSdtPrDataBindingAttrs
.clear();
897 void DocxAttributeOutput::EndSdtBlock()
899 m_pSerializer
->endElementNS( XML_w
, XML_sdtContent
);
900 m_pSerializer
->endElementNS( XML_w
, XML_sdt
);
903 #define MAX_CELL_IN_WORD 62
905 void DocxAttributeOutput::SyncNodelessCells(ww8::WW8TableNodeInfoInner::Pointer_t
const & pInner
, sal_Int32 nCell
, sal_uInt32 nRow
)
907 sal_Int32 nOpenCell
= lastOpenCell
.back();
908 if (nOpenCell
!= -1 && nOpenCell
!= nCell
&& nOpenCell
< MAX_CELL_IN_WORD
)
909 EndTableCell(nOpenCell
);
911 sal_Int32 nClosedCell
= lastClosedCell
.back();
912 for (sal_Int32 i
= nClosedCell
+1; i
< nCell
; ++i
)
914 if (i
>= MAX_CELL_IN_WORD
)
918 StartTableRow(pInner
);
920 StartTableCell(pInner
, i
, nRow
);
921 m_pSerializer
->singleElementNS(XML_w
, XML_p
);
926 void DocxAttributeOutput::FinishTableRowCell( ww8::WW8TableNodeInfoInner::Pointer_t
const & pInner
, bool bForceEmptyParagraph
)
931 // Where are we in the table
932 sal_uInt32 nRow
= pInner
->getRow();
933 sal_Int32 nCell
= pInner
->getCell();
935 InitTableHelper( pInner
);
938 // msoffice seems to have an internal limitation of 63 columns for tables
939 // and refuses to load .docx with more, even though the spec seems to allow that;
940 // so simply if there are more columns, don't close the last one msoffice will handle
941 // and merge the contents of the remaining ones into it (since we don't close the cell
942 // here, following ones will not be opened)
943 const bool limitWorkaround
= (nCell
>= MAX_CELL_IN_WORD
&& !pInner
->isEndOfLine());
944 const bool bEndCell
= pInner
->isEndOfCell() && !limitWorkaround
;
945 const bool bEndRow
= pInner
->isEndOfLine();
949 while (pInner
->getDepth() < m_tableReference
->m_nTableDepth
)
951 //we expect that the higher depth row was closed, and
952 //we are just missing the table close
953 assert(lastOpenCell
.back() == -1 && lastClosedCell
.back() == -1);
957 SyncNodelessCells(pInner
, nCell
, nRow
);
959 sal_Int32 nClosedCell
= lastClosedCell
.back();
960 if (nCell
== nClosedCell
)
962 //Start missing trailing cell(s)
964 StartTableCell(pInner
, nCell
, nRow
);
966 //Continue on missing next trailing cell(s)
967 ww8::RowSpansPtr xRowSpans
= pInner
->getRowSpansOfRow();
968 sal_Int32 nRemainingCells
= xRowSpans
->size() - nCell
;
969 for (sal_Int32 i
= 1; i
< nRemainingCells
; ++i
)
971 if (bForceEmptyParagraph
)
973 m_pSerializer
->singleElementNS(XML_w
, XML_p
);
978 StartTableCell(pInner
, nCell
, nRow
);
982 if (bForceEmptyParagraph
)
984 m_pSerializer
->singleElementNS(XML_w
, XML_p
);
990 // This is a line end
994 // This is the end of the table
995 if (pInner
->isFinalEndOfLine())
999 void DocxAttributeOutput::EmptyParagraph()
1001 m_pSerializer
->singleElementNS(XML_w
, XML_p
);
1004 void DocxAttributeOutput::SectionBreaks(const SwNode
& rNode
)
1006 // output page/section breaks
1007 // Writer can have them at the beginning of a paragraph, or at the end, but
1008 // in docx, we have to output them in the paragraph properties of the last
1009 // paragraph in a section. To get it right, we have to switch to the next
1010 // paragraph, and detect the section breaks there.
1011 SwNodeIndex
aNextIndex( rNode
, 1 );
1013 if (rNode
.IsTextNode() || rNode
.IsSectionNode())
1015 if (aNextIndex
.GetNode().IsTextNode())
1017 const SwTextNode
* pTextNode
= static_cast<SwTextNode
*>(&aNextIndex
.GetNode());
1018 m_rExport
.OutputSectionBreaks(pTextNode
->GetpSwAttrSet(), *pTextNode
, m_tableReference
->m_bTableCellOpen
);
1020 else if (aNextIndex
.GetNode().IsTableNode())
1022 const SwTableNode
* pTableNode
= static_cast<SwTableNode
*>(&aNextIndex
.GetNode());
1023 const SwFrameFormat
*pFormat
= pTableNode
->GetTable().GetFrameFormat();
1024 m_rExport
.OutputSectionBreaks(&(pFormat
->GetAttrSet()), *pTableNode
);
1027 else if (rNode
.IsEndNode())
1029 if (aNextIndex
.GetNode().IsTextNode())
1031 // Handle section break between a table and a text node following it.
1032 // Also handle section endings
1033 const SwTextNode
* pTextNode
= aNextIndex
.GetNode().GetTextNode();
1034 if (rNode
.StartOfSectionNode()->IsTableNode() || rNode
.StartOfSectionNode()->IsSectionNode())
1035 m_rExport
.OutputSectionBreaks(pTextNode
->GetpSwAttrSet(), *pTextNode
, m_tableReference
->m_bTableCellOpen
);
1037 else if (aNextIndex
.GetNode().IsTableNode())
1039 // Handle section break between tables.
1040 const SwTableNode
* pTableNode
= static_cast<SwTableNode
*>(&aNextIndex
.GetNode());
1041 const SwFrameFormat
*pFormat
= pTableNode
->GetTable().GetFrameFormat();
1042 m_rExport
.OutputSectionBreaks(&(pFormat
->GetAttrSet()), *pTableNode
);
1047 void DocxAttributeOutput::StartParagraphProperties()
1049 m_pSerializer
->mark(Tag_StartParagraphProperties
);
1051 m_pSerializer
->startElementNS(XML_w
, XML_pPr
);
1053 // and output the section break now (if it appeared)
1054 if (m_pSectionInfo
&& m_rExport
.m_nTextTyp
== TXT_MAINTEXT
)
1056 m_rExport
.SectionProperties( *m_pSectionInfo
);
1057 m_pSectionInfo
.reset();
1060 InitCollectedParagraphProperties();
1063 void DocxAttributeOutput::InitCollectedParagraphProperties()
1065 m_pParagraphSpacingAttrList
.clear();
1067 // Write the elements in the spec order
1068 static const sal_Int32 aOrder
[] =
1070 FSNS( XML_w
, XML_pStyle
),
1071 FSNS( XML_w
, XML_keepNext
),
1072 FSNS( XML_w
, XML_keepLines
),
1073 FSNS( XML_w
, XML_pageBreakBefore
),
1074 FSNS( XML_w
, XML_framePr
),
1075 FSNS( XML_w
, XML_widowControl
),
1076 FSNS( XML_w
, XML_numPr
),
1077 FSNS( XML_w
, XML_suppressLineNumbers
),
1078 FSNS( XML_w
, XML_pBdr
),
1079 FSNS( XML_w
, XML_shd
),
1080 FSNS( XML_w
, XML_tabs
),
1081 FSNS( XML_w
, XML_suppressAutoHyphens
),
1082 FSNS( XML_w
, XML_kinsoku
),
1083 FSNS( XML_w
, XML_wordWrap
),
1084 FSNS( XML_w
, XML_overflowPunct
),
1085 FSNS( XML_w
, XML_topLinePunct
),
1086 FSNS( XML_w
, XML_autoSpaceDE
),
1087 FSNS( XML_w
, XML_autoSpaceDN
),
1088 FSNS( XML_w
, XML_bidi
),
1089 FSNS( XML_w
, XML_adjustRightInd
),
1090 FSNS( XML_w
, XML_snapToGrid
),
1091 FSNS( XML_w
, XML_spacing
),
1092 FSNS( XML_w
, XML_ind
),
1093 FSNS( XML_w
, XML_contextualSpacing
),
1094 FSNS( XML_w
, XML_mirrorIndents
),
1095 FSNS( XML_w
, XML_suppressOverlap
),
1096 FSNS( XML_w
, XML_jc
),
1097 FSNS( XML_w
, XML_textDirection
),
1098 FSNS( XML_w
, XML_textAlignment
),
1099 FSNS( XML_w
, XML_textboxTightWrap
),
1100 FSNS( XML_w
, XML_outlineLvl
),
1101 FSNS( XML_w
, XML_divId
),
1102 FSNS( XML_w
, XML_cnfStyle
),
1103 FSNS( XML_w
, XML_rPr
),
1104 FSNS( XML_w
, XML_sectPr
),
1105 FSNS( XML_w
, XML_pPrChange
)
1108 // postpone the output so that we can later [in EndParagraphProperties()]
1109 // prepend the properties before the run
1110 m_pSerializer
->mark(Tag_InitCollectedParagraphProperties
, comphelper::containerToSequence(aOrder
));
1113 void DocxAttributeOutput::WriteCollectedParagraphProperties()
1115 if ( m_rExport
.SdrExporter().getFlyAttrList().is() )
1117 XFastAttributeListRef
xAttrList( m_rExport
.SdrExporter().getFlyAttrList().get() );
1118 m_rExport
.SdrExporter().getFlyAttrList().clear();
1120 m_pSerializer
->singleElementNS( XML_w
, XML_framePr
, xAttrList
);
1123 if ( m_pParagraphSpacingAttrList
.is() )
1125 XFastAttributeListRef
xAttrList( m_pParagraphSpacingAttrList
.get() );
1126 m_pParagraphSpacingAttrList
.clear();
1128 m_pSerializer
->singleElementNS( XML_w
, XML_spacing
, xAttrList
);
1131 if ( m_pBackgroundAttrList
.is() )
1133 XFastAttributeListRef
xAttrList( m_pBackgroundAttrList
.get() );
1134 m_pBackgroundAttrList
.clear();
1136 m_pSerializer
->singleElementNS( XML_w
, XML_shd
, xAttrList
);
1143 /// Outputs an item set, that contains the formatting of the paragraph marker.
1144 void lcl_writeParagraphMarkerProperties(DocxAttributeOutput
& rAttributeOutput
, const SfxItemSet
& rParagraphMarkerProperties
)
1146 SfxWhichIter
aIter(rParagraphMarkerProperties
);
1147 sal_uInt16 nWhichId
= aIter
.FirstWhich();
1148 const SfxPoolItem
* pItem
= nullptr;
1149 // Did we already produce a <w:sz> element?
1150 bool bFontSizeWritten
= false;
1153 if (rParagraphMarkerProperties
.GetItemState(nWhichId
, true, &pItem
) == SfxItemState::SET
)
1155 if (isCHRATR(nWhichId
) || nWhichId
== RES_TXTATR_CHARFMT
)
1157 // Will this item produce a <w:sz> element?
1158 bool bFontSizeItem
= nWhichId
== RES_CHRATR_FONTSIZE
|| nWhichId
== RES_CHRATR_CJK_FONTSIZE
;
1159 if (!bFontSizeWritten
|| !bFontSizeItem
)
1160 rAttributeOutput
.OutputItem(*pItem
);
1162 bFontSizeWritten
= true;
1164 else if (nWhichId
== RES_TXTATR_AUTOFMT
)
1166 const SwFormatAutoFormat
* pAutoFormat
= static_cast<const SwFormatAutoFormat
*>(pItem
);
1167 lcl_writeParagraphMarkerProperties(rAttributeOutput
, *pAutoFormat
->GetStyleHandle());
1170 nWhichId
= aIter
.NextWhich();
1174 const char *RubyAlignValues
[] =
1185 const char *lclConvertWW8JCToOOXMLRubyAlign(sal_Int32 nJC
)
1187 const sal_Int32 nElements
= SAL_N_ELEMENTS(RubyAlignValues
);
1188 if ( nJC
>=0 && nJC
< nElements
)
1189 return RubyAlignValues
[nJC
];
1190 return RubyAlignValues
[0];
1195 void DocxAttributeOutput::EndParagraphProperties(const SfxItemSet
& rParagraphMarkerProperties
, const SwRedlineData
* pRedlineData
, const SwRedlineData
* pRedlineParagraphMarkerDeleted
, const SwRedlineData
* pRedlineParagraphMarkerInserted
)
1197 // Call the 'Redline' function. This will add redline (change-tracking) information that regards to paragraph properties.
1198 // This includes changes like 'Bold', 'Underline', 'Strikethrough' etc.
1200 // If there is RedlineData present, call WriteCollectedParagraphProperties() for writing pPr before calling Redline().
1201 // As there will be another pPr for redline and LO might mix both.
1203 WriteCollectedParagraphProperties();
1204 Redline( pRedlineData
);
1206 WriteCollectedParagraphProperties();
1208 // Merge the marks for the ordered elements
1209 m_pSerializer
->mergeTopMarks(Tag_InitCollectedParagraphProperties
);
1211 // Write 'Paragraph Mark' properties
1212 m_pSerializer
->startElementNS(XML_w
, XML_rPr
);
1213 // mark() before paragraph mark properties child elements.
1214 InitCollectedRunProperties();
1216 // The 'm_pFontsAttrList', 'm_pEastAsianLayoutAttrList', 'm_pCharLangAttrList' are used to hold information
1217 // that should be collected by different properties in the core, and are all flushed together
1218 // to the DOCX when the function 'WriteCollectedRunProperties' gets called.
1219 // So we need to store the current status of these lists, so that we can revert back to them when
1220 // we are done exporting the redline attributes.
1221 rtl::Reference
<sax_fastparser::FastAttributeList
> pFontsAttrList_Original(m_pFontsAttrList
);
1222 m_pFontsAttrList
.clear();
1223 rtl::Reference
<sax_fastparser::FastAttributeList
> pEastAsianLayoutAttrList_Original(m_pEastAsianLayoutAttrList
);
1224 m_pEastAsianLayoutAttrList
.clear();
1225 rtl::Reference
<sax_fastparser::FastAttributeList
> pCharLangAttrList_Original(m_pCharLangAttrList
);
1226 m_pCharLangAttrList
.clear();
1228 lcl_writeParagraphMarkerProperties(*this, rParagraphMarkerProperties
);
1230 // Write the collected run properties that are stored in 'm_pFontsAttrList', 'm_pEastAsianLayoutAttrList', 'm_pCharLangAttrList'
1231 WriteCollectedRunProperties();
1233 // Revert back the original values that were stored in 'm_pFontsAttrList', 'm_pEastAsianLayoutAttrList', 'm_pCharLangAttrList'
1234 m_pFontsAttrList
= pFontsAttrList_Original
.get();
1235 m_pEastAsianLayoutAttrList
= pEastAsianLayoutAttrList_Original
.get();
1236 m_pCharLangAttrList
= pCharLangAttrList_Original
.get();
1238 if ( pRedlineParagraphMarkerDeleted
)
1240 StartRedline( pRedlineParagraphMarkerDeleted
);
1241 EndRedline( pRedlineParagraphMarkerDeleted
);
1243 if ( pRedlineParagraphMarkerInserted
)
1245 StartRedline( pRedlineParagraphMarkerInserted
);
1246 EndRedline( pRedlineParagraphMarkerInserted
);
1249 // mergeTopMarks() after paragraph mark properties child elements.
1250 m_pSerializer
->mergeTopMarks(Tag_InitCollectedRunProperties
);
1251 m_pSerializer
->endElementNS( XML_w
, XML_rPr
);
1253 if (!m_bWritingHeaderFooter
&& m_pCurrentFrame
)
1255 const SwFrameFormat
& rFrameFormat
= m_pCurrentFrame
->GetFrameFormat();
1256 const SvxBoxItem
& rBox
= rFrameFormat
.GetBox();
1257 if (TextBoxIsFramePr(rFrameFormat
))
1259 const Size aSize
= m_pCurrentFrame
->GetSize();
1260 PopulateFrameProperties(&rFrameFormat
, aSize
);
1265 m_pSerializer
->endElementNS( XML_w
, XML_pPr
);
1267 // RDF metadata for this text node.
1268 SwTextNode
* pTextNode
= m_rExport
.m_pCurPam
->GetNode().GetTextNode();
1269 std::map
<OUString
, OUString
> aStatements
= SwRDFHelper::getTextNodeStatements("urn:bails", *pTextNode
);
1270 if (!aStatements
.empty())
1272 m_pSerializer
->startElementNS(XML_w
, XML_smartTag
,
1273 FSNS(XML_w
, XML_uri
), "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
1274 FSNS(XML_w
, XML_element
), "RDF");
1275 m_pSerializer
->startElementNS(XML_w
, XML_smartTagPr
);
1276 for (const auto& rStatement
: aStatements
)
1277 m_pSerializer
->singleElementNS(XML_w
, XML_attr
,
1278 FSNS(XML_w
, XML_name
), rStatement
.first
,
1279 FSNS(XML_w
, XML_val
), rStatement
.second
);
1280 m_pSerializer
->endElementNS(XML_w
, XML_smartTagPr
);
1281 m_pSerializer
->endElementNS(XML_w
, XML_smartTag
);
1284 if ( m_nColBreakStatus
== COLBRK_WRITE
|| m_nColBreakStatus
== COLBRK_WRITEANDPOSTPONE
)
1286 m_pSerializer
->startElementNS(XML_w
, XML_r
);
1287 m_pSerializer
->singleElementNS(XML_w
, XML_br
, FSNS(XML_w
, XML_type
), "column");
1288 m_pSerializer
->endElementNS( XML_w
, XML_r
);
1290 if ( m_nColBreakStatus
== COLBRK_WRITEANDPOSTPONE
)
1291 m_nColBreakStatus
= COLBRK_POSTPONE
;
1293 m_nColBreakStatus
= COLBRK_NONE
;
1296 if ( m_bPostponedPageBreak
&& !m_bWritingHeaderFooter
)
1298 m_pSerializer
->startElementNS(XML_w
, XML_r
);
1299 m_pSerializer
->singleElementNS(XML_w
, XML_br
, FSNS(XML_w
, XML_type
), "page");
1300 m_pSerializer
->endElementNS( XML_w
, XML_r
);
1302 m_bPostponedPageBreak
= false;
1305 // merge the properties _before_ the run (strictly speaking, just
1306 // after the start of the paragraph)
1307 m_pSerializer
->mergeTopMarks(Tag_StartParagraphProperties
, sax_fastparser::MergeMarks::PREPEND
);
1310 void DocxAttributeOutput::SetStateOfFlyFrame( FlyProcessingState nStateOfFlyFrame
)
1312 m_nStateOfFlyFrame
= nStateOfFlyFrame
;
1315 void DocxAttributeOutput::SetAnchorIsLinkedToNode( bool bAnchorLinkedToNode
)
1317 m_bAnchorLinkedToNode
= bAnchorLinkedToNode
;
1320 void DocxAttributeOutput::ResetFlyProcessingFlag()
1322 m_bPostponedProcessingFly
= false ;
1325 bool DocxAttributeOutput::IsFlyProcessingPostponed()
1327 return m_bPostponedProcessingFly
;
1330 void DocxAttributeOutput::StartRun( const SwRedlineData
* pRedlineData
, sal_Int32
/*nPos*/, bool /*bSingleEmptyRun*/ )
1332 // Don't start redline data here, possibly there is a hyperlink later, and
1333 // that has to be started first.
1334 m_pRedlineData
= pRedlineData
;
1336 // this mark is used to be able to enclose the run inside a sdr tag.
1337 m_pSerializer
->mark(Tag_StartRun_1
);
1339 // postpone the output of the start of a run (there are elements that need
1340 // to be written before the start of the run, but we learn which they are
1341 // _inside_ of the run)
1342 m_pSerializer
->mark(Tag_StartRun_2
); // let's call it "postponed run start"
1344 // postpone the output of the text (we get it before the run properties,
1345 // but must write it after them)
1346 m_pSerializer
->mark(Tag_StartRun_3
); // let's call it "postponed text"
1349 void DocxAttributeOutput::EndRun(const SwTextNode
* pNode
, sal_Int32 nPos
, bool /*bLastRun*/)
1351 int nFieldsInPrevHyperlink
= m_nFieldsInHyperlink
;
1352 // Reset m_nFieldsInHyperlink if a new hyperlink is about to start
1353 if ( m_pHyperlinkAttrList
.is() )
1355 m_nFieldsInHyperlink
= 0;
1358 // Write field starts
1359 for ( std::vector
<FieldInfos
>::iterator pIt
= m_Fields
.begin() + nFieldsInPrevHyperlink
; pIt
!= m_Fields
.end(); )
1361 // Add the fields starts for all but hyperlinks and TOCs
1362 if (pIt
->bOpen
&& pIt
->pField
&& pIt
->eType
!= ww::eFORMDROPDOWN
)
1364 StartField_Impl( pNode
, nPos
, *pIt
);
1366 // Remove the field from the stack if only the start has to be written
1367 // Unknown fields should be removed too
1368 if ( !pIt
->bClose
|| ( pIt
->eType
== ww::eUNKNOWN
) )
1370 pIt
= m_Fields
.erase( pIt
);
1374 if (m_startedHyperlink
|| m_pHyperlinkAttrList
.is())
1376 ++m_nFieldsInHyperlink
;
1382 // write the run properties + the text, already in the correct order
1383 m_pSerializer
->mergeTopMarks(Tag_StartRun_3
); // merges with "postponed text", see above
1385 // level down, to be able to prepend the actual run start attribute (just
1386 // before "postponed run start")
1387 m_pSerializer
->mark(Tag_EndRun_1
); // let's call it "actual run start"
1388 bool bCloseEarlierSDT
= false;
1392 // This is the common case: "close sdt before the current run" was requested by the next run.
1394 // if another sdt starts in this run, then wait
1395 // as closing the sdt now, might cause nesting of sdts
1396 if (m_nRunSdtPrToken
> 0)
1397 bCloseEarlierSDT
= true;
1400 m_bEndCharSdt
= false;
1401 m_bStartedCharSdt
= false;
1404 if ( m_closeHyperlinkInPreviousRun
)
1406 if ( m_startedHyperlink
)
1408 for ( int i
= 0; i
< nFieldsInPrevHyperlink
; i
++ )
1410 // If fields begin before hyperlink then
1411 // it should end before hyperlink close
1412 EndField_Impl( pNode
, nPos
, m_Fields
.back( ) );
1413 m_Fields
.pop_back();
1415 m_pSerializer
->endElementNS( XML_w
, XML_hyperlink
);
1416 m_startedHyperlink
= false;
1417 m_endPageRef
= false;
1418 m_nHyperLinkCount
--;
1420 m_closeHyperlinkInPreviousRun
= false;
1423 // Write the hyperlink and toc fields starts
1424 for ( std::vector
<FieldInfos
>::iterator pIt
= m_Fields
.begin(); pIt
!= m_Fields
.end(); )
1426 // Add the fields starts for hyperlinks, TOCs and index marks
1427 if (pIt
->bOpen
&& (!pIt
->pField
|| pIt
->eType
== ww::eFORMDROPDOWN
))
1429 StartRedline( m_pRedlineData
);
1430 StartField_Impl( pNode
, nPos
, *pIt
, true );
1431 EndRedline( m_pRedlineData
);
1433 if (m_startedHyperlink
)
1434 ++m_nFieldsInHyperlink
;
1436 // Remove the field if no end needs to be written
1439 pIt
= m_Fields
.erase( pIt
);
1443 if (pIt
->bSep
&& !pIt
->pField
)
1445 CmdEndField_Impl(pNode
, nPos
, true);
1446 // Remove the field if no end needs to be written
1449 pIt
= m_Fields
.erase( pIt
);
1456 // Start the hyperlink after the fields separators or we would generate invalid file
1457 bool newStartedHyperlink(false);
1458 if ( m_pHyperlinkAttrList
.is() )
1460 // if we are ending a hyperlink and there's another one starting here,
1461 // don't do this, so that the fields are closed further down when
1462 // the end hyperlink is handled, which is more likely to put the end in
1463 // the right place, as far as i can tell (not very far in this muck)
1464 if (!m_closeHyperlinkInThisRun
)
1466 // end ToX fields that want to end _before_ starting the hyperlink
1467 for (auto it
= m_Fields
.rbegin(); it
!= m_Fields
.rend(); )
1469 if (it
->bClose
&& !it
->pField
)
1471 EndField_Impl( pNode
, nPos
, *it
);
1472 it
= decltype(m_Fields
)::reverse_iterator(m_Fields
.erase(it
.base() - 1));
1480 newStartedHyperlink
= true;
1482 XFastAttributeListRef
xAttrList ( m_pHyperlinkAttrList
.get() );
1483 m_pHyperlinkAttrList
.clear();
1485 m_pSerializer
->startElementNS( XML_w
, XML_hyperlink
, xAttrList
);
1486 m_startedHyperlink
= true;
1487 m_nHyperLinkCount
++;
1490 // if there is some redlining in the document, output it
1491 StartRedline( m_pRedlineData
);
1493 // XML_r node should be surrounded with bookmark-begin and bookmark-end nodes if it has bookmarks.
1494 // The same is applied for permission ranges.
1495 // But due to unit test "testFdo85542" let's output bookmark-begin with bookmark-end.
1496 DoWriteBookmarksStart(m_rBookmarksStart
);
1497 DoWriteBookmarksEnd(m_rBookmarksEnd
);
1498 DoWritePermissionsStart();
1499 DoWriteAnnotationMarks();
1501 if( m_closeHyperlinkInThisRun
&& m_startedHyperlink
&& !m_hyperLinkAnchor
.isEmpty() && m_hyperLinkAnchor
.startsWith("_Toc"))
1504 m_pSerializer
->startElementNS(XML_w
, XML_r
);
1505 m_pSerializer
->startElementNS(XML_w
, XML_rPr
);
1506 m_pSerializer
->singleElementNS(XML_w
, XML_webHidden
);
1507 m_pSerializer
->endElementNS( XML_w
, XML_rPr
);
1508 m_pSerializer
->startElementNS(XML_w
, XML_fldChar
, FSNS(XML_w
, XML_fldCharType
), "begin");
1509 m_pSerializer
->endElementNS( XML_w
, XML_fldChar
);
1510 m_pSerializer
->endElementNS( XML_w
, XML_r
);
1513 m_pSerializer
->startElementNS(XML_w
, XML_r
);
1514 m_pSerializer
->startElementNS(XML_w
, XML_rPr
);
1515 m_pSerializer
->singleElementNS(XML_w
, XML_webHidden
);
1516 m_pSerializer
->endElementNS( XML_w
, XML_rPr
);
1517 sToken
= "PAGEREF " + m_hyperLinkAnchor
+ " \\h"; // '\h' Creates a hyperlink to the bookmarked paragraph.
1518 DoWriteCmd( sToken
);
1519 m_pSerializer
->endElementNS( XML_w
, XML_r
);
1521 // Write the Field separator
1522 m_pSerializer
->startElementNS(XML_w
, XML_r
);
1523 m_pSerializer
->startElementNS(XML_w
, XML_rPr
);
1524 m_pSerializer
->singleElementNS(XML_w
, XML_webHidden
);
1525 m_pSerializer
->endElementNS( XML_w
, XML_rPr
);
1526 m_pSerializer
->singleElementNS( XML_w
, XML_fldChar
,
1527 FSNS( XML_w
, XML_fldCharType
), "separate" );
1528 m_pSerializer
->endElementNS( XML_w
, XML_r
);
1529 // At start of every "PAGEREF" field m_endPageRef value should be true.
1530 m_endPageRef
= true;
1533 DoWriteBookmarkStartIfExist(nPos
);
1535 m_pSerializer
->startElementNS(XML_w
, XML_r
);
1536 if(GetExport().m_bTabInTOC
&& m_pHyperlinkAttrList
.is())
1540 m_pSerializer
->mergeTopMarks(Tag_EndRun_1
, sax_fastparser::MergeMarks::PREPEND
); // merges with "postponed run start", see above
1542 if ( !m_sRawText
.isEmpty() )
1544 RunText( m_sRawText
);
1548 // write the run start + the run content
1549 m_pSerializer
->mergeTopMarks(Tag_StartRun_2
); // merges the "actual run start"
1550 // append the actual run end
1551 m_pSerializer
->endElementNS( XML_w
, XML_r
);
1553 // if there is some redlining in the document, output it
1554 // (except in the case of fields with multiple runs)
1555 EndRedline( m_pRedlineData
);
1557 // enclose in a sdt block, if necessary: if one is already started, then don't do it for now
1558 // (so on export sdt blocks are never nested ATM)
1559 if ( !m_bAnchorLinkedToNode
&& !m_bStartedCharSdt
)
1561 rtl::Reference
<sax_fastparser::FastAttributeList
> pRunSdtPrTokenAttributes
;
1562 WriteSdtBlock( m_nRunSdtPrToken
, m_pRunSdtPrTokenChildren
, pRunSdtPrTokenAttributes
, m_pRunSdtPrDataBindingAttrs
, m_aRunSdtPrAlias
, /*bPara=*/false );
1566 //These should be written out to the actual Node and not to the anchor.
1567 //Clear them as they will be repopulated when the node is processed.
1568 m_nRunSdtPrToken
= 0;
1569 lcl_deleteAndResetTheLists( m_pRunSdtPrTokenChildren
, m_pRunSdtPrDataBindingAttrs
, m_aRunSdtPrAlias
);
1572 if (bCloseEarlierSDT
)
1574 m_pSerializer
->mark(Tag_EndRun_2
);
1576 m_pSerializer
->mergeTopMarks(Tag_EndRun_2
, sax_fastparser::MergeMarks::PREPEND
);
1579 m_pSerializer
->mergeTopMarks(Tag_StartRun_1
);
1581 // XML_r node should be surrounded with permission-begin and permission-end nodes if it has permission.
1582 DoWritePermissionsEnd();
1584 for (const auto& rpMath
: m_aPostponedMaths
)
1585 WritePostponedMath(rpMath
.pMathObject
, rpMath
.nMathObjAlignment
);
1586 m_aPostponedMaths
.clear();
1588 for (const auto& rpControl
: m_aPostponedFormControls
)
1589 WritePostponedFormControl(rpControl
);
1590 m_aPostponedFormControls
.clear();
1592 WritePostponedActiveXControl(false);
1594 WritePendingPlaceholder();
1596 if ( !m_bWritingField
)
1598 m_pRedlineData
= nullptr;
1601 if ( m_closeHyperlinkInThisRun
)
1603 if ( m_startedHyperlink
)
1607 // Hyperlink is started and fldchar "end" needs to be written for PAGEREF
1608 m_pSerializer
->startElementNS(XML_w
, XML_r
);
1609 m_pSerializer
->startElementNS(XML_w
, XML_rPr
);
1610 m_pSerializer
->singleElementNS(XML_w
, XML_webHidden
);
1611 m_pSerializer
->endElementNS( XML_w
, XML_rPr
);
1612 m_pSerializer
->singleElementNS( XML_w
, XML_fldChar
,
1613 FSNS( XML_w
, XML_fldCharType
), "end" );
1614 m_pSerializer
->endElementNS( XML_w
, XML_r
);
1615 m_endPageRef
= false;
1616 m_hyperLinkAnchor
.clear();
1618 for ( int i
= 0; i
< m_nFieldsInHyperlink
; i
++ )
1620 // If fields begin after hyperlink start then
1621 // it should end before hyperlink close
1622 EndField_Impl( pNode
, nPos
, m_Fields
.back( ) );
1623 m_Fields
.pop_back();
1625 m_nFieldsInHyperlink
= 0;
1627 m_pSerializer
->endElementNS( XML_w
, XML_hyperlink
);
1628 m_startedHyperlink
= false;
1629 m_nHyperLinkCount
--;
1631 m_closeHyperlinkInThisRun
= false;
1634 if (!newStartedHyperlink
)
1636 while ( m_Fields
.begin() != m_Fields
.end() )
1638 EndField_Impl( pNode
, nPos
, m_Fields
.front( ) );
1639 m_Fields
.erase( m_Fields
.begin( ) );
1641 m_nFieldsInHyperlink
= 0;
1645 for (auto it
= m_Fields
.rbegin(); it
!= m_Fields
.rend(); )
1647 if (it
->bClose
&& !it
->pField
)
1649 EndField_Impl( pNode
, nPos
, *it
);
1650 it
= decltype(m_Fields
)::reverse_iterator(m_Fields
.erase(it
.base() - 1));
1658 if ( m_pRedlineData
)
1660 EndRedline( m_pRedlineData
);
1661 m_pRedlineData
= nullptr;
1664 DoWriteBookmarksStart(m_rFinalBookmarksStart
);
1665 DoWriteBookmarksEnd(m_rFinalBookmarksEnd
);
1666 DoWriteBookmarkEndIfExist(nPos
);
1669 void DocxAttributeOutput::DoWriteBookmarkTagStart(const OUString
& bookmarkName
)
1671 m_pSerializer
->singleElementNS(XML_w
, XML_bookmarkStart
,
1672 FSNS(XML_w
, XML_id
), OString::number(m_nNextBookmarkId
),
1673 FSNS(XML_w
, XML_name
), BookmarkToWord(bookmarkName
));
1676 void DocxAttributeOutput::DoWriteBookmarkTagEnd(const OUString
& bookmarkName
)
1678 const auto nameToIdIter
= m_rOpenedBookmarksIds
.find(bookmarkName
);
1679 if (nameToIdIter
!= m_rOpenedBookmarksIds
.end())
1681 const sal_Int32 nId
= nameToIdIter
->second
;
1683 m_pSerializer
->singleElementNS(XML_w
, XML_bookmarkEnd
,
1684 FSNS(XML_w
, XML_id
), OString::number(nId
));
1688 void DocxAttributeOutput::DoWriteBookmarkStartIfExist(sal_Int32 nRunPos
)
1690 auto aRange
= m_aBookmarksOfParagraphStart
.equal_range(nRunPos
);
1691 for( auto aIter
= aRange
.first
; aIter
!= aRange
.second
; ++aIter
)
1693 DoWriteBookmarkTagStart(aIter
->second
);
1694 m_rOpenedBookmarksIds
[aIter
->second
] = m_nNextBookmarkId
;
1695 m_sLastOpenedBookmark
= OUStringToOString(BookmarkToWord(aIter
->second
), RTL_TEXTENCODING_UTF8
);
1696 m_nNextBookmarkId
++;
1700 void DocxAttributeOutput::DoWriteBookmarkEndIfExist(sal_Int32 nRunPos
)
1702 auto aRange
= m_aBookmarksOfParagraphEnd
.equal_range(nRunPos
);
1703 for( auto aIter
= aRange
.first
; aIter
!= aRange
.second
; ++aIter
)
1705 // Get the id of the bookmark
1706 auto pPos
= m_rOpenedBookmarksIds
.find(aIter
->second
);
1707 if (pPos
!= m_rOpenedBookmarksIds
.end())
1709 // Output the bookmark
1710 DoWriteBookmarkTagEnd(aIter
->second
);
1711 m_rOpenedBookmarksIds
.erase(aIter
->second
);
1716 /// Write the start bookmarks
1717 void DocxAttributeOutput::DoWriteBookmarksStart(std::vector
<OUString
>& rStarts
)
1719 for (const OUString
& bookmarkName
: rStarts
)
1721 // Output the bookmark
1722 DoWriteBookmarkTagStart(bookmarkName
);
1724 m_rOpenedBookmarksIds
[bookmarkName
] = m_nNextBookmarkId
;
1725 m_sLastOpenedBookmark
= OUStringToOString(BookmarkToWord(bookmarkName
), RTL_TEXTENCODING_UTF8
);
1726 m_nNextBookmarkId
++;
1731 /// export the end bookmarks
1732 void DocxAttributeOutput::DoWriteBookmarksEnd(std::vector
<OUString
>& rEnds
)
1734 for (const OUString
& bookmarkName
: rEnds
)
1736 // Get the id of the bookmark
1737 auto pPos
= m_rOpenedBookmarksIds
.find(bookmarkName
);
1738 if (pPos
!= m_rOpenedBookmarksIds
.end())
1740 // Output the bookmark
1741 DoWriteBookmarkTagEnd(bookmarkName
);
1743 m_rOpenedBookmarksIds
.erase(bookmarkName
);
1749 // For construction of the special bookmark name template for permissions:
1750 // see, PermInsertPosition::createBookmarkName()
1753 // - "permission-for-user:<permission-id>:<permission-user-name>"
1754 // - "permission-for-group:<permission-id>:<permission-group-name>"
1756 void DocxAttributeOutput::DoWritePermissionTagStart(const OUString
& permission
)
1758 OUString permissionIdAndName
;
1760 if (permission
.startsWith("permission-for-group:", &permissionIdAndName
))
1762 const sal_Int32 sparatorIndex
= permissionIdAndName
.indexOf(':');
1763 const OUString permissionId
= permissionIdAndName
.copy(0, sparatorIndex
);
1764 const OUString permissionName
= permissionIdAndName
.copy(sparatorIndex
+ 1);
1766 m_pSerializer
->singleElementNS(XML_w
, XML_permStart
,
1767 FSNS(XML_w
, XML_id
), BookmarkToWord(permissionId
),
1768 FSNS(XML_w
, XML_edGrp
), BookmarkToWord(permissionName
));
1770 else // if (permission.startsWith("permission-for-user:", &permissionIdAndName))
1772 const sal_Int32 sparatorIndex
= permissionIdAndName
.indexOf(':');
1773 const OUString permissionId
= permissionIdAndName
.copy(0, sparatorIndex
);
1774 const OUString permissionName
= permissionIdAndName
.copy(sparatorIndex
+ 1);
1776 m_pSerializer
->singleElementNS(XML_w
, XML_permStart
,
1777 FSNS(XML_w
, XML_id
), BookmarkToWord(permissionId
),
1778 FSNS(XML_w
, XML_ed
), BookmarkToWord(permissionName
));
1783 // For construction of the special bookmark name template for permissions:
1784 // see, PermInsertPosition::createBookmarkName()
1787 // - "permission-for-user:<permission-id>:<permission-user-name>"
1788 // - "permission-for-group:<permission-id>:<permission-group-name>"
1790 void DocxAttributeOutput::DoWritePermissionTagEnd(const OUString
& permission
)
1792 OUString permissionIdAndName
;
1794 if (permission
.startsWith("permission-for-group:", &permissionIdAndName
) ||
1795 permission
.startsWith("permission-for-user:", &permissionIdAndName
))
1797 const sal_Int32 sparatorIndex
= permissionIdAndName
.indexOf(':');
1798 const OUString permissionId
= permissionIdAndName
.copy(0, sparatorIndex
);
1800 m_pSerializer
->singleElementNS(XML_w
, XML_permEnd
,
1801 FSNS(XML_w
, XML_id
), BookmarkToWord(permissionId
));
1805 /// Write the start permissions
1806 void DocxAttributeOutput::DoWritePermissionsStart()
1808 for (const OUString
& permission
: m_rPermissionsStart
)
1810 DoWritePermissionTagStart(permission
);
1812 m_rPermissionsStart
.clear();
1815 /// export the end permissions
1816 void DocxAttributeOutput::DoWritePermissionsEnd()
1818 for (const OUString
& permission
: m_rPermissionsEnd
)
1820 DoWritePermissionTagEnd(permission
);
1822 m_rPermissionsEnd
.clear();
1825 void DocxAttributeOutput::DoWriteAnnotationMarks()
1827 // Write the start annotation marks
1828 for ( const auto & rName
: m_rAnnotationMarksStart
)
1830 // Output the annotation mark
1831 /* Ensure that the existing Annotation Marks are not overwritten
1832 as it causes discrepancy when DocxAttributeOutput::PostitField
1833 refers to this map & while mapping comment id's in document.xml &
1836 if ( m_rOpenedAnnotationMarksIds
.end() == m_rOpenedAnnotationMarksIds
.find( rName
) )
1838 const sal_Int32 nId
= m_nNextAnnotationMarkId
++;
1839 m_rOpenedAnnotationMarksIds
[rName
] = nId
;
1840 m_pSerializer
->singleElementNS( XML_w
, XML_commentRangeStart
,
1841 FSNS( XML_w
, XML_id
), OString::number(nId
) );
1842 m_sLastOpenedAnnotationMark
= rName
;
1845 m_rAnnotationMarksStart
.clear();
1847 // export the end annotation marks
1848 for ( const auto & rName
: m_rAnnotationMarksEnd
)
1850 // Get the id of the annotation mark
1851 std::map
< OString
, sal_Int32
>::iterator pPos
= m_rOpenedAnnotationMarksIds
.find( rName
);
1852 if ( pPos
!= m_rOpenedAnnotationMarksIds
.end( ) )
1854 const sal_Int32 nId
= ( *pPos
).second
;
1855 m_pSerializer
->singleElementNS( XML_w
, XML_commentRangeEnd
,
1856 FSNS( XML_w
, XML_id
), OString::number(nId
) );
1857 m_rOpenedAnnotationMarksIds
.erase( rName
);
1859 m_pSerializer
->startElementNS(XML_w
, XML_r
);
1860 m_pSerializer
->singleElementNS( XML_w
, XML_commentReference
, FSNS( XML_w
, XML_id
),
1861 OString::number(nId
) );
1862 m_pSerializer
->endElementNS(XML_w
, XML_r
);
1865 m_rAnnotationMarksEnd
.clear();
1868 void DocxAttributeOutput::WriteFFData( const FieldInfos
& rInfos
)
1870 const ::sw::mark::IFieldmark
& rFieldmark
= *rInfos
.pFieldmark
;
1871 FieldMarkParamsHelper
params( rFieldmark
);
1873 OUString sEntryMacro
;
1874 params
.extractParam("EntryMacro", sEntryMacro
);
1875 OUString sExitMacro
;
1876 params
.extractParam("ExitMacro", sExitMacro
);
1878 params
.extractParam("Help", sHelp
);
1880 params
.extractParam("Hint", sHint
); // .docx StatusText
1881 if ( sHint
.isEmpty() )
1882 params
.extractParam("Description", sHint
); // .doc StatusText
1884 if ( rInfos
.eType
== ww::eFORMDROPDOWN
)
1886 uno::Sequence
< OUString
> vListEntries
;
1887 OUString sName
, sSelected
;
1889 params
.extractParam( ODF_FORMDROPDOWN_LISTENTRY
, vListEntries
);
1890 if (vListEntries
.getLength() > ODF_FORMDROPDOWN_ENTRY_COUNT_LIMIT
)
1891 vListEntries
= uno::Sequence
< OUString
>(vListEntries
.getArray(), ODF_FORMDROPDOWN_ENTRY_COUNT_LIMIT
);
1893 sName
= params
.getName();
1894 sal_Int32 nSelectedIndex
= 0;
1896 if ( params
.extractParam( ODF_FORMDROPDOWN_RESULT
, nSelectedIndex
) )
1898 if (nSelectedIndex
< vListEntries
.getLength() )
1899 sSelected
= vListEntries
[ nSelectedIndex
];
1902 GetExport().DoComboBox( sName
, OUString(), OUString(), sSelected
, vListEntries
);
1904 else if ( rInfos
.eType
== ww::eFORMCHECKBOX
)
1907 bool bChecked
= false;
1909 params
.extractParam( ODF_FORMCHECKBOX_NAME
, sName
);
1911 const sw::mark::ICheckboxFieldmark
* pCheckboxFm
= dynamic_cast<const sw::mark::ICheckboxFieldmark
*>(&rFieldmark
);
1912 if ( pCheckboxFm
&& pCheckboxFm
->IsChecked() )
1915 FFDataWriterHelper
ffdataOut( m_pSerializer
);
1916 ffdataOut
.WriteFormCheckbox( sName
, sEntryMacro
, sExitMacro
, sHelp
, sHint
, bChecked
);
1918 else if ( rInfos
.eType
== ww::eFORMTEXT
)
1921 params
.extractParam("Type", sType
);
1922 OUString sDefaultText
;
1923 params
.extractParam("Content", sDefaultText
);
1924 sal_uInt16 nMaxLength
= 0;
1925 params
.extractParam("MaxLength", nMaxLength
);
1927 params
.extractParam("Format", sFormat
);
1928 FFDataWriterHelper
ffdataOut( m_pSerializer
);
1929 ffdataOut
.WriteFormText( params
.getName(), sEntryMacro
, sExitMacro
, sHelp
, sHint
,
1930 sType
, sDefaultText
, nMaxLength
, sFormat
);
1934 void DocxAttributeOutput::WriteFormDateStart(const OUString
& sFullDate
, const OUString
& sDateFormat
, const OUString
& sLang
)
1936 m_pSerializer
->startElementNS(XML_w
, XML_sdt
);
1937 m_pSerializer
->startElementNS(XML_w
, XML_sdtPr
);
1939 if(!sFullDate
.isEmpty())
1940 m_pSerializer
->startElementNS(XML_w
, XML_date
, FSNS(XML_w
, XML_fullDate
), sFullDate
);
1942 m_pSerializer
->startElementNS(XML_w
, XML_date
);
1944 // Replace quotation mark used for marking static strings in date format
1945 OUString sDateFormat1
= sDateFormat
.replaceAll("\"", "'");
1946 m_pSerializer
->singleElementNS(XML_w
, XML_dateFormat
,
1947 FSNS(XML_w
, XML_val
), sDateFormat1
);
1948 m_pSerializer
->singleElementNS(XML_w
, XML_lid
,
1949 FSNS(XML_w
, XML_val
), sLang
);
1950 m_pSerializer
->singleElementNS(XML_w
, XML_storeMappedDataAs
,
1951 FSNS(XML_w
, XML_val
), "dateTime");
1952 m_pSerializer
->singleElementNS(XML_w
, XML_calendar
,
1953 FSNS(XML_w
, XML_val
), "gregorian");
1955 m_pSerializer
->endElementNS(XML_w
, XML_date
);
1956 m_pSerializer
->endElementNS(XML_w
, XML_sdtPr
);
1958 m_pSerializer
->startElementNS(XML_w
, XML_sdtContent
);
1961 void DocxAttributeOutput::WriteSdtEnd()
1963 m_pSerializer
->endElementNS(XML_w
, XML_sdtContent
);
1964 m_pSerializer
->endElementNS(XML_w
, XML_sdt
);
1967 void DocxAttributeOutput::WriteSdtDropDownStart(
1968 OUString
const& rName
,
1969 OUString
const& rSelected
,
1970 uno::Sequence
<OUString
> const& rListItems
)
1972 m_pSerializer
->startElementNS(XML_w
, XML_sdt
);
1973 m_pSerializer
->startElementNS(XML_w
, XML_sdtPr
);
1975 m_pSerializer
->singleElementNS(XML_w
, XML_alias
,
1976 FSNS(XML_w
, XML_val
), OUStringToOString(rName
, RTL_TEXTENCODING_UTF8
));
1978 sal_Int32 nId
= comphelper::findValue(rListItems
, rSelected
);
1984 m_pSerializer
->startElementNS(XML_w
, XML_dropDownList
,
1985 FSNS(XML_w
, XML_lastValue
), OString::number(nId
));
1987 for (auto const& rItem
: rListItems
)
1989 auto const item(OUStringToOString(rItem
, RTL_TEXTENCODING_UTF8
));
1990 m_pSerializer
->singleElementNS(XML_w
, XML_listItem
,
1991 FSNS(XML_w
, XML_value
), item
,
1992 FSNS(XML_w
, XML_displayText
), item
);
1995 m_pSerializer
->endElementNS(XML_w
, XML_dropDownList
);
1996 m_pSerializer
->endElementNS(XML_w
, XML_sdtPr
);
1998 m_pSerializer
->startElementNS(XML_w
, XML_sdtContent
);
2001 void DocxAttributeOutput::WriteSdtDropDownEnd(OUString
const& rSelected
,
2002 uno::Sequence
<OUString
> const& rListItems
)
2004 // note: rSelected might be empty?
2005 sal_Int32 nId
= comphelper::findValue(rListItems
, rSelected
);
2011 // the lastValue only identifies the entry in the list, also export
2012 // currently selected item's displayText as run content (if one exists)
2013 if (rListItems
.size())
2015 m_pSerializer
->startElementNS(XML_w
, XML_r
);
2016 m_pSerializer
->startElementNS(XML_w
, XML_t
);
2017 m_pSerializer
->writeEscaped(rListItems
[nId
]);
2018 m_pSerializer
->endElementNS(XML_w
, XML_t
);
2019 m_pSerializer
->endElementNS(XML_w
, XML_r
);
2025 void DocxAttributeOutput::StartField_Impl( const SwTextNode
* pNode
, sal_Int32 nPos
, FieldInfos
const & rInfos
, bool bWriteRun
)
2027 if ( rInfos
.pField
&& rInfos
.eType
== ww::eUNKNOWN
)
2029 // Expand unsupported fields
2030 RunText( rInfos
.pField
->GetFieldName() );
2032 else if ( rInfos
.eType
== ww::eFORMDATE
)
2034 const sw::mark::IDateFieldmark
& rFieldmark
= dynamic_cast<const sw::mark::IDateFieldmark
&>(*rInfos
.pFieldmark
);
2035 FieldMarkParamsHelper
params(rFieldmark
);
2038 OUString sCurrentDate
;
2039 params
.extractParam( ODF_FORMDATE_CURRENTDATE
, sCurrentDate
);
2040 if(!sCurrentDate
.isEmpty())
2042 sFullDate
= sCurrentDate
+ "T00:00:00Z";
2046 std::pair
<bool, double> aResult
= rFieldmark
.GetCurrentDate();
2049 sFullDate
= rFieldmark
.GetDateInStandardDateFormat(aResult
.second
) + "T00:00:00Z";
2053 OUString sDateFormat
;
2054 params
.extractParam( ODF_FORMDATE_DATEFORMAT
, sDateFormat
);
2056 params
.extractParam( ODF_FORMDATE_DATEFORMAT_LANGUAGE
, sLang
);
2058 WriteFormDateStart( sFullDate
, sDateFormat
, sLang
);
2060 else if (rInfos
.eType
== ww::eFORMDROPDOWN
&& rInfos
.pField
)
2062 assert(!rInfos
.pFieldmark
);
2063 SwDropDownField
const& rField2(*static_cast<SwDropDownField
const*>(rInfos
.pField
.get()));
2064 WriteSdtDropDownStart(rField2
.GetName(),
2065 rField2
.GetSelectedItem(),
2066 rField2
.GetItemSequence());
2068 else if ( rInfos
.eType
!= ww::eNONE
) // HYPERLINK fields are just commands
2071 m_pSerializer
->startElementNS(XML_w
, XML_r
);
2073 if ( rInfos
.eType
== ww::eFORMDROPDOWN
)
2075 m_pSerializer
->startElementNS( XML_w
, XML_fldChar
,
2076 FSNS( XML_w
, XML_fldCharType
), "begin" );
2077 assert( rInfos
.pFieldmark
&& !rInfos
.pField
);
2078 WriteFFData(rInfos
);
2079 m_pSerializer
->endElementNS( XML_w
, XML_fldChar
);
2082 m_pSerializer
->endElementNS( XML_w
, XML_r
);
2084 CmdField_Impl( pNode
, nPos
, rInfos
, bWriteRun
);
2088 // Write the field start
2089 if ( rInfos
.pField
&& (rInfos
.pField
->Which() == SwFieldIds::DateTime
) && rInfos
.pField
->GetSubType() & FIXEDFLD
)
2091 m_pSerializer
->startElementNS( XML_w
, XML_fldChar
,
2092 FSNS( XML_w
, XML_fldCharType
), "begin",
2093 FSNS( XML_w
, XML_fldLock
), "true" );
2097 m_pSerializer
->startElementNS( XML_w
, XML_fldChar
,
2098 FSNS( XML_w
, XML_fldCharType
), "begin" );
2101 if ( rInfos
.pFieldmark
)
2102 WriteFFData( rInfos
);
2104 m_pSerializer
->endElementNS( XML_w
, XML_fldChar
);
2107 m_pSerializer
->endElementNS( XML_w
, XML_r
);
2109 // The hyperlinks fields can't be expanded: the value is
2110 // normally in the text run
2111 if ( !rInfos
.pField
)
2112 CmdField_Impl( pNode
, nPos
, rInfos
, bWriteRun
);
2114 m_bWritingField
= true;
2119 void DocxAttributeOutput::DoWriteCmd( const OUString
& rCmd
)
2121 OUString sCmd
= rCmd
.trim();
2122 if (sCmd
.startsWith("SEQ"))
2124 OUString sSeqName
= msfilter::util::findQuotedText(sCmd
, "SEQ ", '\\').trim();
2125 m_aSeqBookmarksNames
[sSeqName
].push_back(m_sLastOpenedBookmark
);
2127 // Write the Field command
2128 sal_Int32 nTextToken
= XML_instrText
;
2129 if ( m_pRedlineData
&& m_pRedlineData
->GetType() == RedlineType::Delete
)
2130 nTextToken
= XML_delInstrText
;
2132 m_pSerializer
->startElementNS(XML_w
, nTextToken
);
2133 m_pSerializer
->writeEscaped( rCmd
);
2134 m_pSerializer
->endElementNS( XML_w
, nTextToken
);
2138 void DocxAttributeOutput::CmdField_Impl( const SwTextNode
* pNode
, sal_Int32 nPos
, FieldInfos
const & rInfos
, bool bWriteRun
)
2140 // Write the Field instruction
2143 bool bWriteCombChars(false);
2144 m_pSerializer
->startElementNS(XML_w
, XML_r
);
2146 if (rInfos
.eType
== ww::eEQ
)
2147 bWriteCombChars
= true;
2149 DoWriteFieldRunProperties( pNode
, nPos
, bWriteCombChars
);
2152 sal_Int32 nIdx
{ rInfos
.sCmd
.isEmpty() ? -1 : 0 };
2155 OUString sToken
= rInfos
.sCmd
.getToken( 0, '\t', nIdx
);
2156 if ( rInfos
.eType
== ww::eCREATEDATE
2157 || rInfos
.eType
== ww::eSAVEDATE
2158 || rInfos
.eType
== ww::ePRINTDATE
2159 || rInfos
.eType
== ww::eDATE
2160 || rInfos
.eType
== ww::eTIME
)
2162 sToken
= sToken
.replaceAll("NNNN", "dddd");
2163 sToken
= sToken
.replaceAll("NN", "ddd");
2165 else if ( rInfos
.eType
== ww::eEquals
)
2167 // Use original OOXML formula, if it exists and its conversion hasn't been changed
2168 bool bIsChanged
= true;
2169 if ( pNode
->GetTableBox() )
2171 if ( const SfxGrabBagItem
* pItem
= pNode
->GetTableBox()->GetFrameFormat()->GetAttrSet().GetItem
<SfxGrabBagItem
>(RES_FRMATR_GRABBAG
) )
2173 OUString sActualFormula
= sToken
.trim();
2174 const std::map
<OUString
, uno::Any
>& rGrabBag
= pItem
->GetGrabBag();
2175 std::map
<OUString
, uno::Any
>::const_iterator aStoredFormula
= rGrabBag
.find("CellFormulaConverted");
2176 if ( aStoredFormula
!= rGrabBag
.end() && sActualFormula
.indexOf('=') == 0 &&
2177 sActualFormula
.copy(1).trim() == aStoredFormula
->second
.get
<OUString
>().trim() )
2179 aStoredFormula
= rGrabBag
.find("CellFormula");
2180 if ( aStoredFormula
!= rGrabBag
.end() )
2182 sToken
= " =" + aStoredFormula
->second
.get
<OUString
>();
2191 UErrorCode
nErr(U_ZERO_ERROR
);
2192 icu::UnicodeString
sInput(sToken
.getStr());
2193 // remove < and > around cell references, e.g. <A1> to A1, <A1:B2> to A1:B2
2194 icu::RegexMatcher
aMatcher("<([A-Z]{1,3}[0-9]+(:[A-Z]{1,3}[0-9]+)?)>", sInput
, 0, nErr
);
2195 sInput
= aMatcher
.replaceAll(icu::UnicodeString("$1"), nErr
);
2196 // convert MEAN to AVERAGE
2197 icu::RegexMatcher
aMatcher2("\\bMEAN\\b", sInput
, UREGEX_CASE_INSENSITIVE
, nErr
);
2198 sToken
= aMatcher2
.replaceAll(icu::UnicodeString("AVERAGE"), nErr
).getTerminatedBuffer();
2202 // Write the Field command
2203 DoWriteCmd( sToken
);
2205 // Replace tabs by </instrText><tab/><instrText>
2206 if ( nIdx
> 0 ) // Is another token expected?
2212 m_pSerializer
->endElementNS( XML_w
, XML_r
);
2216 void DocxAttributeOutput::CmdEndField_Impl(SwTextNode
const*const pNode
,
2217 sal_Int32
const nPos
, bool const bWriteRun
)
2219 // Write the Field separator
2222 m_pSerializer
->startElementNS(XML_w
, XML_r
);
2223 DoWriteFieldRunProperties( pNode
, nPos
);
2226 m_pSerializer
->singleElementNS( XML_w
, XML_fldChar
,
2227 FSNS( XML_w
, XML_fldCharType
), "separate" );
2231 m_pSerializer
->endElementNS( XML_w
, XML_r
);
2235 /// Writes properties for run that is used to separate field implementation.
2236 /// There are several runs are used:
2239 /// <!-- properties written with StartRunProperties() / EndRunProperties().
2241 /// <w:fldChar w:fldCharType="begin" />
2245 /// <!-- properties written with DoWriteFieldRunProperties()
2247 /// <w:instrText>TIME \@"HH:mm:ss"</w:instrText>
2251 /// <!-- properties written with DoWriteFieldRunProperties()
2253 /// <w:fldChar w:fldCharType="separate" />
2257 /// <!-- properties written with DoWriteFieldRunProperties()
2259 /// <w:t>14:01:13</w:t>
2263 /// <!-- properties written with DoWriteFieldRunProperties()
2265 /// <w:fldChar w:fldCharType="end" />
2268 void DocxAttributeOutput::DoWriteFieldRunProperties( const SwTextNode
* pNode
, sal_Int32 nPos
, bool bWriteCombChars
)
2276 m_bPreventDoubleFieldsHandling
= true;
2279 m_pSerializer
->startElementNS(XML_w
, XML_rPr
);
2281 // 1. output webHidden flag
2282 if(GetExport().m_bHideTabLeaderAndPageNumbers
&& m_pHyperlinkAttrList
.is() )
2284 m_pSerializer
->singleElementNS(XML_w
, XML_webHidden
);
2287 // 2. find all active character properties
2288 SwWW8AttrIter
aAttrIt( m_rExport
, *pNode
);
2289 aAttrIt
.OutAttr( nPos
, bWriteCombChars
);
2291 // 3. write the character properties
2292 WriteCollectedRunProperties();
2294 m_pSerializer
->endElementNS( XML_w
, XML_rPr
);
2297 m_bPreventDoubleFieldsHandling
= false;
2300 void DocxAttributeOutput::EndField_Impl( const SwTextNode
* pNode
, sal_Int32 nPos
, FieldInfos
& rInfos
)
2302 if (rInfos
.eType
== ww::eFORMDATE
)
2307 if (rInfos
.eType
== ww::eFORMDROPDOWN
&& rInfos
.pField
)
2309 // write selected item from End not Start to ensure that any bookmarks
2311 SwDropDownField
const& rField(*static_cast<SwDropDownField
const*>(rInfos
.pField
.get()));
2312 WriteSdtDropDownEnd(rField
.GetSelectedItem(), rField
.GetItemSequence());
2316 // The command has to be written before for the hyperlinks
2317 if ( rInfos
.pField
)
2319 CmdField_Impl( pNode
, nPos
, rInfos
, true );
2320 CmdEndField_Impl( pNode
, nPos
, true );
2323 // Write the bookmark start if any
2324 if ( !m_sFieldBkm
.isEmpty() )
2326 DoWriteBookmarkTagStart(m_sFieldBkm
);
2329 if (rInfos
.pField
) // For hyperlinks and TOX
2331 // Write the Field latest value
2332 m_pSerializer
->startElementNS(XML_w
, XML_r
);
2333 DoWriteFieldRunProperties( pNode
, nPos
);
2336 if(rInfos
.eType
== ww::eCITATION
)
2338 sExpand
= static_cast<SwAuthorityField
const*>(rInfos
.pField
.get())
2339 ->ExpandCitation(AUTH_FIELD_TITLE
, nullptr);
2341 else if(rInfos
.eType
!= ww::eFORMDROPDOWN
)
2343 sExpand
= rInfos
.pField
->ExpandField(true, nullptr);
2345 // newlines embedded in fields are 0x0B in MSO and 0x0A for us
2346 RunText(sExpand
.replace(0x0A, 0x0B));
2348 m_pSerializer
->endElementNS( XML_w
, XML_r
);
2351 // Write the bookmark end if any
2352 if ( !m_sFieldBkm
.isEmpty() )
2354 DoWriteBookmarkTagEnd(m_sFieldBkm
);
2356 m_nNextBookmarkId
++;
2359 // Write the Field end
2360 if ( rInfos
.bClose
)
2362 m_bWritingField
= false;
2363 m_pSerializer
->startElementNS(XML_w
, XML_r
);
2364 DoWriteFieldRunProperties( pNode
, nPos
);
2365 m_pSerializer
->singleElementNS(XML_w
, XML_fldChar
, FSNS(XML_w
, XML_fldCharType
), "end");
2366 m_pSerializer
->endElementNS( XML_w
, XML_r
);
2368 // Write the ref field if a bookmark had to be set and the field
2369 // should be visible
2370 if ( !rInfos
.pField
)
2373 sal_uInt16 nSubType
= rInfos
.pField
->GetSubType( );
2374 bool bIsSetField
= rInfos
.pField
->GetTyp( )->Which( ) == SwFieldIds::SetExp
;
2375 bool bShowRef
= bIsSetField
&& ( nSubType
& nsSwExtendedSubType::SUB_INVISIBLE
) == 0;
2377 if ( m_sFieldBkm
.isEmpty() || !bShowRef
)
2380 // Write the field beginning
2381 m_pSerializer
->startElementNS(XML_w
, XML_r
);
2382 m_pSerializer
->singleElementNS( XML_w
, XML_fldChar
,
2383 FSNS( XML_w
, XML_fldCharType
), "begin" );
2384 m_pSerializer
->endElementNS( XML_w
, XML_r
);
2386 rInfos
.sCmd
= FieldString( ww::eREF
);
2387 rInfos
.sCmd
+= "\"";
2388 rInfos
.sCmd
+= m_sFieldBkm
;
2389 rInfos
.sCmd
+= "\" ";
2391 // Clean the field bookmark data to avoid infinite loop
2392 m_sFieldBkm
= OUString( );
2394 // Write the end of the field
2395 EndField_Impl( pNode
, nPos
, rInfos
);
2398 void DocxAttributeOutput::StartRunProperties()
2400 // postpone the output so that we can later [in EndRunProperties()]
2401 // prepend the properties before the text
2402 m_pSerializer
->mark(Tag_StartRunProperties
);
2404 m_pSerializer
->startElementNS(XML_w
, XML_rPr
);
2406 if(GetExport().m_bHideTabLeaderAndPageNumbers
&& m_pHyperlinkAttrList
.is() )
2408 m_pSerializer
->singleElementNS(XML_w
, XML_webHidden
);
2410 InitCollectedRunProperties();
2412 assert( !m_pPostponedGraphic
);
2413 m_pPostponedGraphic
.reset(new std::vector
<PostponedGraphic
>);
2415 assert( !m_pPostponedDiagrams
);
2416 m_pPostponedDiagrams
.reset(new std::vector
<PostponedDiagram
>);
2418 assert(!m_pPostponedDMLDrawings
);
2419 m_pPostponedDMLDrawings
.reset(new std::vector
<PostponedDrawing
>);
2421 assert( !m_pPostponedOLEs
);
2422 m_pPostponedOLEs
.reset(new std::vector
<PostponedOLE
>);
2425 void DocxAttributeOutput::InitCollectedRunProperties()
2427 m_pFontsAttrList
= nullptr;
2428 m_pEastAsianLayoutAttrList
= nullptr;
2429 m_pCharLangAttrList
= nullptr;
2431 // Write the elements in the spec order
2432 static const sal_Int32 aOrder
[] =
2434 FSNS( XML_w
, XML_rStyle
),
2435 FSNS( XML_w
, XML_rFonts
),
2436 FSNS( XML_w
, XML_b
),
2437 FSNS( XML_w
, XML_bCs
),
2438 FSNS( XML_w
, XML_i
),
2439 FSNS( XML_w
, XML_iCs
),
2440 FSNS( XML_w
, XML_caps
),
2441 FSNS( XML_w
, XML_smallCaps
),
2442 FSNS( XML_w
, XML_strike
),
2443 FSNS( XML_w
, XML_dstrike
),
2444 FSNS( XML_w
, XML_outline
),
2445 FSNS( XML_w
, XML_shadow
),
2446 FSNS( XML_w
, XML_emboss
),
2447 FSNS( XML_w
, XML_imprint
),
2448 FSNS( XML_w
, XML_noProof
),
2449 FSNS( XML_w
, XML_snapToGrid
),
2450 FSNS( XML_w
, XML_vanish
),
2451 FSNS( XML_w
, XML_webHidden
),
2452 FSNS( XML_w
, XML_color
),
2453 FSNS( XML_w
, XML_spacing
),
2454 FSNS( XML_w
, XML_w
),
2455 FSNS( XML_w
, XML_kern
),
2456 FSNS( XML_w
, XML_position
),
2457 FSNS( XML_w
, XML_sz
),
2458 FSNS( XML_w
, XML_szCs
),
2459 FSNS( XML_w
, XML_highlight
),
2460 FSNS( XML_w
, XML_u
),
2461 FSNS( XML_w
, XML_effect
),
2462 FSNS( XML_w
, XML_bdr
),
2463 FSNS( XML_w
, XML_shd
),
2464 FSNS( XML_w
, XML_fitText
),
2465 FSNS( XML_w
, XML_vertAlign
),
2466 FSNS( XML_w
, XML_rtl
),
2467 FSNS( XML_w
, XML_cs
),
2468 FSNS( XML_w
, XML_em
),
2469 FSNS( XML_w
, XML_lang
),
2470 FSNS( XML_w
, XML_eastAsianLayout
),
2471 FSNS( XML_w
, XML_specVanish
),
2472 FSNS( XML_w
, XML_oMath
),
2473 FSNS( XML_w
, XML_rPrChange
),
2474 FSNS( XML_w
, XML_del
),
2475 FSNS( XML_w14
, XML_glow
),
2476 FSNS( XML_w14
, XML_shadow
),
2477 FSNS( XML_w14
, XML_reflection
),
2478 FSNS( XML_w14
, XML_textOutline
),
2479 FSNS( XML_w14
, XML_textFill
),
2480 FSNS( XML_w14
, XML_scene3d
),
2481 FSNS( XML_w14
, XML_props3d
),
2482 FSNS( XML_w14
, XML_ligatures
),
2483 FSNS( XML_w14
, XML_numForm
),
2484 FSNS( XML_w14
, XML_numSpacing
),
2485 FSNS( XML_w14
, XML_stylisticSets
),
2486 FSNS( XML_w14
, XML_cntxtAlts
),
2489 // postpone the output so that we can later [in EndParagraphProperties()]
2490 // prepend the properties before the run
2491 m_pSerializer
->mark(Tag_InitCollectedRunProperties
, comphelper::containerToSequence(aOrder
));
2503 const NameToId constNameToIdMapping
[] =
2505 { OUString("glow"), FSNS( XML_w14
, XML_glow
) },
2506 { OUString("shadow"), FSNS( XML_w14
, XML_shadow
) },
2507 { OUString("reflection"), FSNS( XML_w14
, XML_reflection
) },
2508 { OUString("textOutline"), FSNS( XML_w14
, XML_textOutline
) },
2509 { OUString("textFill"), FSNS( XML_w14
, XML_textFill
) },
2510 { OUString("scene3d"), FSNS( XML_w14
, XML_scene3d
) },
2511 { OUString("props3d"), FSNS( XML_w14
, XML_props3d
) },
2512 { OUString("ligatures"), FSNS( XML_w14
, XML_ligatures
) },
2513 { OUString("numForm"), FSNS( XML_w14
, XML_numForm
) },
2514 { OUString("numSpacing"), FSNS( XML_w14
, XML_numSpacing
) },
2515 { OUString("stylisticSets"),FSNS( XML_w14
, XML_stylisticSets
) },
2516 { OUString("cntxtAlts"), FSNS( XML_w14
, XML_cntxtAlts
) },
2518 { OUString("val"), FSNS( XML_w14
, XML_val
) },
2519 { OUString("rad"), FSNS( XML_w14
, XML_rad
) },
2520 { OUString("blurRad"), FSNS( XML_w14
, XML_blurRad
) },
2521 { OUString("stA"), FSNS( XML_w14
, XML_stA
) },
2522 { OUString("stPos"), FSNS( XML_w14
, XML_stPos
) },
2523 { OUString("endA"), FSNS( XML_w14
, XML_endA
) },
2524 { OUString("endPos"), FSNS( XML_w14
, XML_endPos
) },
2525 { OUString("dist"), FSNS( XML_w14
, XML_dist
) },
2526 { OUString("dir"), FSNS( XML_w14
, XML_dir
) },
2527 { OUString("fadeDir"), FSNS( XML_w14
, XML_fadeDir
) },
2528 { OUString("sx"), FSNS( XML_w14
, XML_sx
) },
2529 { OUString("sy"), FSNS( XML_w14
, XML_sy
) },
2530 { OUString("kx"), FSNS( XML_w14
, XML_kx
) },
2531 { OUString("ky"), FSNS( XML_w14
, XML_ky
) },
2532 { OUString("algn"), FSNS( XML_w14
, XML_algn
) },
2533 { OUString("w"), FSNS( XML_w14
, XML_w
) },
2534 { OUString("cap"), FSNS( XML_w14
, XML_cap
) },
2535 { OUString("cmpd"), FSNS( XML_w14
, XML_cmpd
) },
2536 { OUString("pos"), FSNS( XML_w14
, XML_pos
) },
2537 { OUString("ang"), FSNS( XML_w14
, XML_ang
) },
2538 { OUString("scaled"), FSNS( XML_w14
, XML_scaled
) },
2539 { OUString("path"), FSNS( XML_w14
, XML_path
) },
2540 { OUString("l"), FSNS( XML_w14
, XML_l
) },
2541 { OUString("t"), FSNS( XML_w14
, XML_t
) },
2542 { OUString("r"), FSNS( XML_w14
, XML_r
) },
2543 { OUString("b"), FSNS( XML_w14
, XML_b
) },
2544 { OUString("lim"), FSNS( XML_w14
, XML_lim
) },
2545 { OUString("prst"), FSNS( XML_w14
, XML_prst
) },
2546 { OUString("rig"), FSNS( XML_w14
, XML_rig
) },
2547 { OUString("lat"), FSNS( XML_w14
, XML_lat
) },
2548 { OUString("lon"), FSNS( XML_w14
, XML_lon
) },
2549 { OUString("rev"), FSNS( XML_w14
, XML_rev
) },
2550 { OUString("h"), FSNS( XML_w14
, XML_h
) },
2551 { OUString("extrusionH"), FSNS( XML_w14
, XML_extrusionH
) },
2552 { OUString("contourW"), FSNS( XML_w14
, XML_contourW
) },
2553 { OUString("prstMaterial"), FSNS( XML_w14
, XML_prstMaterial
) },
2554 { OUString("id"), FSNS( XML_w14
, XML_id
) },
2556 { OUString("schemeClr"), FSNS( XML_w14
, XML_schemeClr
) },
2557 { OUString("srgbClr"), FSNS( XML_w14
, XML_srgbClr
) },
2558 { OUString("tint"), FSNS( XML_w14
, XML_tint
) },
2559 { OUString("shade"), FSNS( XML_w14
, XML_shade
) },
2560 { OUString("alpha"), FSNS( XML_w14
, XML_alpha
) },
2561 { OUString("hueMod"), FSNS( XML_w14
, XML_hueMod
) },
2562 { OUString("sat"), FSNS( XML_w14
, XML_sat
) },
2563 { OUString("satOff"), FSNS( XML_w14
, XML_satOff
) },
2564 { OUString("satMod"), FSNS( XML_w14
, XML_satMod
) },
2565 { OUString("lum"), FSNS( XML_w14
, XML_lum
) },
2566 { OUString("lumOff"), FSNS( XML_w14
, XML_lumOff
) },
2567 { OUString("lumMod"), FSNS( XML_w14
, XML_lumMod
) },
2568 { OUString("noFill"), FSNS( XML_w14
, XML_noFill
) },
2569 { OUString("solidFill"), FSNS( XML_w14
, XML_solidFill
) },
2570 { OUString("gradFill"), FSNS( XML_w14
, XML_gradFill
) },
2571 { OUString("gsLst"), FSNS( XML_w14
, XML_gsLst
) },
2572 { OUString("gs"), FSNS( XML_w14
, XML_gs
) },
2573 { OUString("pos"), FSNS( XML_w14
, XML_pos
) },
2574 { OUString("lin"), FSNS( XML_w14
, XML_lin
) },
2575 { OUString("path"), FSNS( XML_w14
, XML_path
) },
2576 { OUString("fillToRect"), FSNS( XML_w14
, XML_fillToRect
) },
2577 { OUString("prstDash"), FSNS( XML_w14
, XML_prstDash
) },
2578 { OUString("round"), FSNS( XML_w14
, XML_round
) },
2579 { OUString("bevel"), FSNS( XML_w14
, XML_bevel
) },
2580 { OUString("miter"), FSNS( XML_w14
, XML_miter
) },
2581 { OUString("camera"), FSNS( XML_w14
, XML_camera
) },
2582 { OUString("lightRig"), FSNS( XML_w14
, XML_lightRig
) },
2583 { OUString("rot"), FSNS( XML_w14
, XML_rot
) },
2584 { OUString("bevelT"), FSNS( XML_w14
, XML_bevelT
) },
2585 { OUString("bevelB"), FSNS( XML_w14
, XML_bevelB
) },
2586 { OUString("extrusionClr"), FSNS( XML_w14
, XML_extrusionClr
) },
2587 { OUString("contourClr"), FSNS( XML_w14
, XML_contourClr
) },
2588 { OUString("styleSet"), FSNS( XML_w14
, XML_styleSet
) },
2591 std::optional
<sal_Int32
> lclGetElementIdForName(const OUString
& rName
)
2593 for (auto const & i
: constNameToIdMapping
)
2595 if (rName
== i
.maName
)
2600 return std::optional
<sal_Int32
>();
2603 void lclProcessRecursiveGrabBag(sal_Int32 aElementId
, const css::uno::Sequence
<css::beans::PropertyValue
>& rElements
, sax_fastparser::FSHelperPtr
const & pSerializer
)
2605 css::uno::Sequence
<css::beans::PropertyValue
> aAttributes
;
2606 FastAttributeList
* pAttributes
= FastSerializerHelper::createAttrList();
2608 for (const auto& rElement
: rElements
)
2610 if (rElement
.Name
== "attributes")
2612 rElement
.Value
>>= aAttributes
;
2616 for (const auto& rAttribute
: std::as_const(aAttributes
))
2618 uno::Any aAny
= rAttribute
.Value
;
2621 if(aAny
.getValueType() == cppu::UnoType
<sal_Int32
>::get())
2623 aValue
= OString::number(aAny
.get
<sal_Int32
>());
2625 else if(aAny
.getValueType() == cppu::UnoType
<OUString
>::get())
2627 aValue
= OUStringToOString(aAny
.get
<OUString
>(), RTL_TEXTENCODING_ASCII_US
);
2630 std::optional
<sal_Int32
> aSubElementId
= lclGetElementIdForName(rAttribute
.Name
);
2632 pAttributes
->add(*aSubElementId
, aValue
.getStr());
2635 XFastAttributeListRef
xAttributesList( pAttributes
);
2637 pSerializer
->startElement(aElementId
, xAttributesList
);
2639 for (const auto& rElement
: rElements
)
2641 css::uno::Sequence
<css::beans::PropertyValue
> aSumElements
;
2643 std::optional
<sal_Int32
> aSubElementId
= lclGetElementIdForName(rElement
.Name
);
2646 rElement
.Value
>>= aSumElements
;
2647 lclProcessRecursiveGrabBag(*aSubElementId
, aSumElements
, pSerializer
);
2651 pSerializer
->endElement(aElementId
);
2656 void DocxAttributeOutput::WriteCollectedRunProperties()
2658 // Write all differed properties
2659 if ( m_pFontsAttrList
.is() )
2661 XFastAttributeListRef
xAttrList( m_pFontsAttrList
.get() );
2662 m_pFontsAttrList
.clear();
2663 m_pSerializer
->singleElementNS( XML_w
, XML_rFonts
, xAttrList
);
2666 if ( m_pColorAttrList
.is() )
2668 XFastAttributeListRef
xAttrList( m_pColorAttrList
.get() );
2670 m_pSerializer
->singleElementNS( XML_w
, XML_color
, xAttrList
);
2673 if ( m_pEastAsianLayoutAttrList
.is() )
2675 XFastAttributeListRef
xAttrList( m_pEastAsianLayoutAttrList
.get() );
2676 m_pEastAsianLayoutAttrList
.clear();
2677 m_pSerializer
->singleElementNS( XML_w
, XML_eastAsianLayout
, xAttrList
);
2680 if ( m_pCharLangAttrList
.is() )
2682 XFastAttributeListRef
xAttrList( m_pCharLangAttrList
.get() );
2683 m_pCharLangAttrList
.clear();
2684 m_pSerializer
->singleElementNS( XML_w
, XML_lang
, xAttrList
);
2687 if (m_nCharTransparence
!= 0 && m_pColorAttrList
&& m_aTextEffectsGrabBag
.empty())
2689 const char* pVal
= nullptr;
2690 m_pColorAttrList
->getAsChar(FSNS(XML_w
, XML_val
), pVal
);
2691 if (OString("auto") != pVal
)
2693 m_pSerializer
->startElementNS(XML_w14
, XML_textFill
);
2694 m_pSerializer
->startElementNS(XML_w14
, XML_solidFill
);
2695 m_pSerializer
->startElementNS(XML_w14
, XML_srgbClr
, FSNS(XML_w14
, XML_val
), pVal
);
2696 sal_Int32 nTransparence
= m_nCharTransparence
* oox::drawingml::MAX_PERCENT
/ 255.0;
2697 m_pSerializer
->singleElementNS(XML_w14
, XML_alpha
, FSNS(XML_w14
, XML_val
), OString::number(nTransparence
));
2698 m_pSerializer
->endElementNS(XML_w14
, XML_srgbClr
);
2699 m_pSerializer
->endElementNS(XML_w14
, XML_solidFill
);
2700 m_pSerializer
->endElementNS(XML_w14
, XML_textFill
);
2701 m_nCharTransparence
= 0;
2704 m_pColorAttrList
.clear();
2705 for (const beans::PropertyValue
& i
: m_aTextEffectsGrabBag
)
2707 std::optional
<sal_Int32
> aElementId
= lclGetElementIdForName(i
.Name
);
2710 uno::Sequence
<beans::PropertyValue
> aGrabBagSeq
;
2711 i
.Value
>>= aGrabBagSeq
;
2712 lclProcessRecursiveGrabBag(*aElementId
, aGrabBagSeq
, m_pSerializer
);
2715 m_aTextEffectsGrabBag
.clear();
2718 void DocxAttributeOutput::EndRunProperties( const SwRedlineData
* pRedlineData
)
2720 // Call the 'Redline' function. This will add redline (change-tracking) information that regards to run properties.
2721 // This includes changes like 'Bold', 'Underline', 'Strikethrough' etc.
2722 Redline( pRedlineData
);
2724 WriteCollectedRunProperties();
2726 // Merge the marks for the ordered elements
2727 m_pSerializer
->mergeTopMarks(Tag_InitCollectedRunProperties
);
2729 m_pSerializer
->endElementNS( XML_w
, XML_rPr
);
2731 // write footnotes/endnotes if we have any
2732 FootnoteEndnoteReference();
2734 // merge the properties _before_ the run text (strictly speaking, just
2735 // after the start of the run)
2736 m_pSerializer
->mergeTopMarks(Tag_StartRunProperties
, sax_fastparser::MergeMarks::PREPEND
);
2738 WritePostponedGraphic();
2740 WritePostponedDiagram();
2741 //We need to write w:drawing tag after the w:rPr.
2742 WritePostponedChart();
2744 //We need to write w:pict tag after the w:rPr.
2745 WritePostponedDMLDrawing();
2747 WritePostponedOLE();
2749 WritePostponedActiveXControl(true);
2752 void DocxAttributeOutput::GetSdtEndBefore(const SdrObject
* pSdrObj
)
2757 uno::Reference
<drawing::XShape
> xShape(const_cast<SdrObject
*>(pSdrObj
)->getUnoShape(), uno::UNO_QUERY_THROW
);
2758 uno::Reference
< beans::XPropertySet
> xPropSet( xShape
, uno::UNO_QUERY
);
2759 if( !xPropSet
.is() )
2762 uno::Reference
< beans::XPropertySetInfo
> xPropSetInfo
= xPropSet
->getPropertySetInfo();
2763 uno::Sequence
< beans::PropertyValue
> aGrabBag
;
2764 if (xPropSetInfo
.is() && xPropSetInfo
->hasPropertyByName("FrameInteropGrabBag"))
2766 xPropSet
->getPropertyValue("FrameInteropGrabBag") >>= aGrabBag
;
2768 else if(xPropSetInfo
.is() && xPropSetInfo
->hasPropertyByName("InteropGrabBag"))
2770 xPropSet
->getPropertyValue("InteropGrabBag") >>= aGrabBag
;
2773 auto pProp
= std::find_if(aGrabBag
.begin(), aGrabBag
.end(),
2774 [this](const beans::PropertyValue
& rProp
) {
2775 return "SdtEndBefore" == rProp
.Name
&& m_bStartedCharSdt
&& !m_bEndCharSdt
; });
2776 if (pProp
!= aGrabBag
.end())
2777 pProp
->Value
>>= m_bEndCharSdt
;
2780 void DocxAttributeOutput::WritePostponedGraphic()
2782 for (const auto & rPostponedDiagram
: *m_pPostponedGraphic
)
2783 FlyFrameGraphic(rPostponedDiagram
.grfNode
, rPostponedDiagram
.size
,
2785 rPostponedDiagram
.pSdrObj
);
2786 m_pPostponedGraphic
.reset();
2789 void DocxAttributeOutput::WritePostponedDiagram()
2791 for( const auto & rPostponedDiagram
: *m_pPostponedDiagrams
)
2792 m_rExport
.SdrExporter().writeDiagram(rPostponedDiagram
.object
,
2793 *rPostponedDiagram
.frame
, m_anchorId
++);
2794 m_pPostponedDiagrams
.reset();
2797 bool DocxAttributeOutput::FootnoteEndnoteRefTag()
2799 if( m_footnoteEndnoteRefTag
== 0 )
2802 // output the character style for MS Word's benefit
2803 const SwEndNoteInfo
& rInfo
= m_footnoteEndnoteRefTag
== XML_footnoteRef
?
2804 m_rExport
.m_rDoc
.GetFootnoteInfo() : m_rExport
.m_rDoc
.GetEndNoteInfo();
2805 const SwCharFormat
* pCharFormat
= rInfo
.GetCharFormat( m_rExport
.m_rDoc
);
2808 const OString
aStyleId(m_rExport
.m_pStyles
->GetStyleId(m_rExport
.GetId(pCharFormat
)));
2809 m_pSerializer
->startElementNS(XML_w
, XML_rPr
);
2810 m_pSerializer
->singleElementNS(XML_w
, XML_rStyle
, FSNS(XML_w
, XML_val
), aStyleId
);
2811 m_pSerializer
->endElementNS( XML_w
, XML_rPr
);
2814 if (m_footnoteCustomLabel
.isEmpty())
2815 m_pSerializer
->singleElementNS(XML_w
, m_footnoteEndnoteRefTag
);
2817 RunText(m_footnoteCustomLabel
);
2818 m_footnoteEndnoteRefTag
= 0;
2822 /** Output sal_Unicode* as a run text (<t>the text</t>).
2824 When bMove is true, update rBegin to point _after_ the end of the text +
2825 1, meaning that it skips one character after the text. This is to make
2826 the switch in DocxAttributeOutput::RunText() nicer ;-)
2828 static bool impl_WriteRunText( FSHelperPtr
const & pSerializer
, sal_Int32 nTextToken
,
2829 const sal_Unicode
* &rBegin
, const sal_Unicode
* pEnd
, bool bMove
= true )
2831 const sal_Unicode
*pBegin
= rBegin
;
2833 // skip one character after the end
2837 if ( pBegin
>= pEnd
)
2838 return false; // we want to write at least one character
2840 // we have to add 'preserve' when starting/ending with space
2841 if ( *pBegin
== ' ' || *( pEnd
- 1 ) == ' ' )
2843 pSerializer
->startElementNS(XML_w
, nTextToken
, FSNS(XML_xml
, XML_space
), "preserve");
2846 pSerializer
->startElementNS(XML_w
, nTextToken
);
2848 pSerializer
->writeEscaped( OUString( pBegin
, pEnd
- pBegin
) );
2850 pSerializer
->endElementNS( XML_w
, nTextToken
);
2855 void DocxAttributeOutput::RunText( const OUString
& rText
, rtl_TextEncoding
/*eCharSet*/ )
2857 if( m_closeHyperlinkInThisRun
)
2859 m_closeHyperlinkInPreviousRun
= true;
2861 m_bRunTextIsOn
= true;
2862 // one text can be split into more <w:t>blah</w:t>'s by line breaks etc.
2863 const sal_Unicode
*pBegin
= rText
.getStr();
2864 const sal_Unicode
*pEnd
= pBegin
+ rText
.getLength();
2866 // the text run is usually XML_t, with the exception of the deleted text
2867 sal_Int32 nTextToken
= XML_t
;
2868 if ( m_pRedlineData
&& m_pRedlineData
->GetType() == RedlineType::Delete
)
2869 nTextToken
= XML_delText
;
2871 sal_Unicode prevUnicode
= *pBegin
;
2873 for ( const sal_Unicode
*pIt
= pBegin
; pIt
< pEnd
; ++pIt
)
2878 impl_WriteRunText( m_pSerializer
, nTextToken
, pBegin
, pIt
);
2879 m_pSerializer
->singleElementNS(XML_w
, XML_tab
);
2882 case 0x0b: // line break
2884 if (impl_WriteRunText( m_pSerializer
, nTextToken
, pBegin
, pIt
) || prevUnicode
< 0x0020)
2886 m_pSerializer
->singleElementNS(XML_w
, XML_br
);
2891 case 0x1E: //non-breaking hyphen
2892 impl_WriteRunText( m_pSerializer
, nTextToken
, pBegin
, pIt
);
2893 m_pSerializer
->singleElementNS(XML_w
, XML_noBreakHyphen
);
2896 case 0x1F: //soft (on demand) hyphen
2897 impl_WriteRunText( m_pSerializer
, nTextToken
, pBegin
, pIt
);
2898 m_pSerializer
->singleElementNS(XML_w
, XML_softHyphen
);
2902 if ( *pIt
< 0x0020 ) // filter out the control codes
2904 impl_WriteRunText( m_pSerializer
, nTextToken
, pBegin
, pIt
);
2905 SAL_INFO("sw.ww8", "Ignored control code in a text run: " << unsigned(*pIt
) );
2912 impl_WriteRunText( m_pSerializer
, nTextToken
, pBegin
, pEnd
, false );
2915 void DocxAttributeOutput::RawText(const OUString
& rText
, rtl_TextEncoding
/*eCharSet*/)
2920 void DocxAttributeOutput::StartRuby( const SwTextNode
& rNode
, sal_Int32 nPos
, const SwFormatRuby
& rRuby
)
2922 WW8Ruby
aWW8Ruby( rNode
, rRuby
, GetExport() );
2923 SAL_INFO("sw.ww8", "TODO DocxAttributeOutput::StartRuby( const SwTextNode& rNode, const SwFormatRuby& rRuby )" );
2924 EndRun( &rNode
, nPos
); // end run before starting ruby to avoid nested runs, and overlap
2925 assert(!m_closeHyperlinkInThisRun
); // check that no hyperlink overlaps ruby
2926 assert(!m_closeHyperlinkInPreviousRun
);
2927 m_pSerializer
->startElementNS(XML_w
, XML_r
);
2928 m_pSerializer
->startElementNS(XML_w
, XML_ruby
);
2929 m_pSerializer
->startElementNS(XML_w
, XML_rubyPr
);
2931 m_pSerializer
->singleElementNS( XML_w
, XML_rubyAlign
,
2932 FSNS( XML_w
, XML_val
), lclConvertWW8JCToOOXMLRubyAlign(aWW8Ruby
.GetJC()) );
2933 sal_uInt32 nHps
= (aWW8Ruby
.GetRubyHeight() + 5) / 10;
2934 sal_uInt32 nHpsBaseText
= (aWW8Ruby
.GetBaseHeight() + 5) / 10;
2935 m_pSerializer
->singleElementNS(XML_w
, XML_hps
, FSNS(XML_w
, XML_val
), OString::number(nHps
));
2937 m_pSerializer
->singleElementNS( XML_w
, XML_hpsRaise
,
2938 FSNS( XML_w
, XML_val
), OString::number(nHpsBaseText
) );
2940 m_pSerializer
->singleElementNS( XML_w
, XML_hpsBaseText
,
2941 FSNS( XML_w
, XML_val
), OString::number(nHpsBaseText
) );
2943 lang::Locale
aLocale( SwBreakIt::Get()->GetLocale(
2944 rNode
.GetLang( nPos
) ) );
2945 OUString
sLang( LanguageTag::convertToBcp47( aLocale
) );
2946 m_pSerializer
->singleElementNS(XML_w
, XML_lid
, FSNS(XML_w
, XML_val
), sLang
);
2948 m_pSerializer
->endElementNS( XML_w
, XML_rubyPr
);
2950 m_pSerializer
->startElementNS(XML_w
, XML_rt
);
2951 StartRun( nullptr, nPos
);
2952 StartRunProperties( );
2954 if (rRuby
.GetTextRuby() && rRuby
.GetTextRuby()->GetCharFormat())
2956 const SwCharFormat
* pFormat
= rRuby
.GetTextRuby()->GetCharFormat();
2957 sal_uInt16 nScript
= g_pBreakIt
->GetBreakIter()->getScriptType(rRuby
.GetText(), 0);
2958 sal_uInt16 nWhichFont
= (nScript
== i18n::ScriptType::LATIN
) ? RES_CHRATR_FONT
: RES_CHRATR_CJK_FONT
;
2959 sal_uInt16 nWhichFontSize
= (nScript
== i18n::ScriptType::LATIN
) ? RES_CHRATR_FONTSIZE
: RES_CHRATR_CJK_FONTSIZE
;
2961 CharFont(ItemGet
<SvxFontItem
>(*pFormat
, nWhichFont
));
2962 CharFontSize(ItemGet
<SvxFontHeightItem
>(*pFormat
, nWhichFontSize
));
2963 CharFontSize(ItemGet
<SvxFontHeightItem
>(*pFormat
, RES_CHRATR_CTL_FONTSIZE
));
2966 EndRunProperties( nullptr );
2967 RunText( rRuby
.GetText( ) );
2968 EndRun( &rNode
, nPos
);
2969 m_pSerializer
->endElementNS( XML_w
, XML_rt
);
2971 m_pSerializer
->startElementNS(XML_w
, XML_rubyBase
);
2972 StartRun( nullptr, nPos
);
2975 void DocxAttributeOutput::EndRuby(const SwTextNode
& rNode
, sal_Int32 nPos
)
2977 SAL_INFO("sw.ww8", "TODO DocxAttributeOutput::EndRuby()" );
2978 EndRun( &rNode
, nPos
);
2979 m_pSerializer
->endElementNS( XML_w
, XML_rubyBase
);
2980 m_pSerializer
->endElementNS( XML_w
, XML_ruby
);
2981 m_pSerializer
->endElementNS( XML_w
, XML_r
);
2982 StartRun(nullptr, nPos
); // open Run again so OutputTextNode loop can close it
2985 bool DocxAttributeOutput::AnalyzeURL( const OUString
& rUrl
, const OUString
& rTarget
, OUString
* pLinkURL
, OUString
* pMark
)
2987 bool bBookMarkOnly
= AttributeOutputBase::AnalyzeURL( rUrl
, rTarget
, pLinkURL
, pMark
);
2989 if ( !pMark
->isEmpty() )
2991 OUString sURL
= *pLinkURL
;
2993 if ( bBookMarkOnly
)
2994 sURL
= FieldString( ww::eHYPERLINK
);
2996 sURL
= FieldString( ww::eHYPERLINK
) + "\"" + sURL
+ "\"";
2998 sURL
+= " \\l \"" + *pMark
+ "\"";
3000 if ( !rTarget
.isEmpty() )
3001 sURL
+= " \\n " + rTarget
;
3006 return bBookMarkOnly
;
3009 void DocxAttributeOutput::WriteBookmarkInActParagraph( const OUString
& rName
, sal_Int32 nFirstRunPos
, sal_Int32 nLastRunPos
)
3011 m_aBookmarksOfParagraphStart
.insert(std::pair
<sal_Int32
, OUString
>(nFirstRunPos
, rName
));
3012 m_aBookmarksOfParagraphEnd
.insert(std::pair
<sal_Int32
, OUString
>(nLastRunPos
, rName
));
3015 bool DocxAttributeOutput::StartURL( const OUString
& rUrl
, const OUString
& rTarget
)
3020 bool bBookmarkOnly
= AnalyzeURL( rUrl
, rTarget
, &sUrl
, &sMark
);
3022 m_hyperLinkAnchor
= sMark
;
3024 if ( !sMark
.isEmpty() && !bBookmarkOnly
)
3026 m_rExport
.OutputField( nullptr, ww::eHYPERLINK
, sUrl
);
3030 // Output a hyperlink XML element
3031 m_pHyperlinkAttrList
= FastSerializerHelper::createAttrList();
3033 if ( !bBookmarkOnly
)
3035 OString sId
= OUStringToOString( GetExport().GetFilter().addRelation( m_pSerializer
->getOutputStream(),
3036 oox::getRelationship(Relationship::HYPERLINK
),
3037 sUrl
, true ), RTL_TEXTENCODING_UTF8
);
3039 m_pHyperlinkAttrList
->add( FSNS( XML_r
, XML_id
), sId
.getStr());
3043 // Is this a link to a sequence? Then try to replace that with a
3044 // normal bookmark, as Word won't understand our special
3045 // <seqname>!<index>|sequence syntax.
3046 if (sMark
.endsWith("|sequence"))
3048 sal_Int32 nPos
= sMark
.indexOf('!');
3051 // Extract <seqname>, the field instruction text has the name quoted.
3052 OUString aSequenceName
= sMark
.copy(0, nPos
);
3054 sal_uInt32 nIndex
= sMark
.copy(nPos
+ 1, sMark
.getLength() - nPos
- sizeof("|sequence")).toUInt32();
3055 std::map
<OUString
, std::vector
<OString
> >::iterator it
= m_aSeqBookmarksNames
.find(aSequenceName
);
3056 if (it
!= m_aSeqBookmarksNames
.end())
3058 std::vector
<OString
>& rNames
= it
->second
;
3059 if (rNames
.size() > nIndex
)
3060 // We know the bookmark name for this sequence and this index, do the replacement.
3061 sMark
= OStringToOUString(rNames
[nIndex
], RTL_TEXTENCODING_UTF8
);
3065 // Spaces are prohibited in bookmark name.
3066 sMark
= sMark
.replace(' ', '_');
3067 m_pHyperlinkAttrList
->add( FSNS( XML_w
, XML_anchor
),
3068 OUStringToOString( sMark
, RTL_TEXTENCODING_UTF8
).getStr( ) );
3071 if ( !rTarget
.isEmpty() )
3073 OString soTarget
= OUStringToOString( rTarget
, RTL_TEXTENCODING_UTF8
);
3074 m_pHyperlinkAttrList
->add(FSNS( XML_w
, XML_tgtFrame
), soTarget
.getStr());
3081 bool DocxAttributeOutput::EndURL(bool const)
3083 m_closeHyperlinkInThisRun
= true;
3084 if(m_startedHyperlink
&& !m_hyperLinkAnchor
.isEmpty() && m_hyperLinkAnchor
.startsWith("_Toc"))
3086 m_endPageRef
= true;
3091 void DocxAttributeOutput::FieldVanish( const OUString
& rText
, ww::eField eType
)
3093 WriteField_Impl( nullptr, eType
, rText
, FieldFlags::All
);
3096 // The difference between 'Redline' and 'StartRedline'+'EndRedline' is that:
3097 // 'Redline' is used for tracked changes of formatting information of a run like Bold, Underline. (the '<w:rPrChange>' is inside the 'run' node)
3098 // 'StartRedline' is used to output tracked changes of run insertion and deletion (the run is inside the '<w:ins>' node)
3099 void DocxAttributeOutput::Redline( const SwRedlineData
* pRedlineData
)
3101 if ( !pRedlineData
)
3104 OString
aId( OString::number( pRedlineData
->GetSeqNo() ) );
3105 const OUString
&rAuthor( SW_MOD()->GetRedlineAuthor( pRedlineData
->GetAuthor() ) );
3106 OString
aDate( DateTimeToOString( pRedlineData
->GetTimeStamp() ) );
3108 switch( pRedlineData
->GetType() )
3110 case RedlineType::Insert
:
3113 case RedlineType::Delete
:
3116 case RedlineType::Format
:
3117 m_pSerializer
->startElementNS( XML_w
, XML_rPrChange
,
3118 FSNS( XML_w
, XML_id
), aId
,
3119 FSNS( XML_w
, XML_author
), rAuthor
,
3120 FSNS( XML_w
, XML_date
), aDate
);
3122 m_pSerializer
->endElementNS( XML_w
, XML_rPrChange
);
3125 case RedlineType::ParagraphFormat
:
3126 m_pSerializer
->startElementNS( XML_w
, XML_pPrChange
,
3127 FSNS( XML_w
, XML_id
), aId
,
3128 FSNS( XML_w
, XML_author
), rAuthor
,
3129 FSNS( XML_w
, XML_date
), aDate
);
3131 // Check if there is any extra data stored in the redline object
3132 if (pRedlineData
->GetExtraData())
3134 const SwRedlineExtraData
* pExtraData
= pRedlineData
->GetExtraData();
3135 const SwRedlineExtraData_FormatColl
* pFormattingChanges
= dynamic_cast<const SwRedlineExtraData_FormatColl
*>(pExtraData
);
3137 // Check if the extra data is of type 'formatting changes'
3138 if (pFormattingChanges
)
3140 // Get the item set that holds all the changes properties
3141 const SfxItemSet
*pChangesSet
= pFormattingChanges
->GetItemSet();
3142 const OUString
& sParaStyleName
= pFormattingChanges
->GetFormatName();
3143 if (pChangesSet
|| !sParaStyleName
.isEmpty())
3145 m_pSerializer
->mark(Tag_Redline_2
);
3147 m_pSerializer
->startElementNS(XML_w
, XML_pPr
);
3149 OString sStyleName
= MSWordStyles::CreateStyleId( sParaStyleName
);
3150 if ( !sStyleName
.isEmpty() )
3151 m_pSerializer
->singleElementNS(XML_w
, XML_pStyle
, FSNS(XML_w
, XML_val
), sStyleName
);
3153 // The 'm_rExport.SdrExporter().getFlyAttrList()', 'm_pParagraphSpacingAttrList' are used to hold information
3154 // that should be collected by different properties in the core, and are all flushed together
3155 // to the DOCX when the function 'WriteCollectedParagraphProperties' gets called.
3156 // So we need to store the current status of these lists, so that we can revert back to them when
3157 // we are done exporting the redline attributes.
3158 rtl::Reference
<sax_fastparser::FastAttributeList
> pFlyAttrList_Original(m_rExport
.SdrExporter().getFlyAttrList());
3159 m_rExport
.SdrExporter().getFlyAttrList().clear();
3160 rtl::Reference
<sax_fastparser::FastAttributeList
> pParagraphSpacingAttrList_Original(m_pParagraphSpacingAttrList
);
3161 m_pParagraphSpacingAttrList
.clear();
3163 // Output the redline item set
3165 m_rExport
.OutputItemSet( *pChangesSet
, true, false, i18n::ScriptType::LATIN
, m_rExport
.m_bExportModeRTF
);
3167 // Write the collected paragraph properties that are stored in 'm_rExport.SdrExporter().getFlyAttrList()', 'm_pParagraphSpacingAttrList'
3168 WriteCollectedParagraphProperties();
3170 // Revert back the original values that were stored in 'm_rExport.SdrExporter().getFlyAttrList()', 'm_pParagraphSpacingAttrList'
3171 m_rExport
.SdrExporter().getFlyAttrList() = pFlyAttrList_Original
;
3172 m_pParagraphSpacingAttrList
= pParagraphSpacingAttrList_Original
;
3174 m_pSerializer
->endElementNS( XML_w
, XML_pPr
);
3176 m_pSerializer
->mergeTopMarks(Tag_Redline_2
, sax_fastparser::MergeMarks::PREPEND
);
3180 m_pSerializer
->endElementNS( XML_w
, XML_pPrChange
);
3184 SAL_WARN("sw.ww8", "Unhandled redline type for export " << SwRedlineTypeToOUString(pRedlineData
->GetType()));
3189 // The difference between 'Redline' and 'StartRedline'+'EndRedline' is that:
3190 // 'Redline' is used for tracked changes of formatting information of a run like Bold, Underline. (the '<w:rPrChange>' is inside the 'run' node)
3191 // 'StartRedline' is used to output tracked changes of run insertion and deletion (the run is inside the '<w:ins>' node)
3192 void DocxAttributeOutput::StartRedline( const SwRedlineData
* pRedlineData
)
3194 if ( !pRedlineData
)
3197 // FIXME check if it's necessary to travel over the Next()'s in pRedlineData
3199 OString
aId( OString::number( m_nRedlineId
++ ) );
3201 const OUString
&rAuthor( SW_MOD()->GetRedlineAuthor( pRedlineData
->GetAuthor() ) );
3202 OString
aAuthor( OUStringToOString( rAuthor
, RTL_TEXTENCODING_UTF8
) );
3204 OString
aDate( DateTimeToOString( pRedlineData
->GetTimeStamp() ) );
3206 switch ( pRedlineData
->GetType() )
3208 case RedlineType::Insert
:
3209 m_pSerializer
->startElementNS( XML_w
, XML_ins
,
3210 FSNS( XML_w
, XML_id
), aId
,
3211 FSNS( XML_w
, XML_author
), aAuthor
,
3212 FSNS( XML_w
, XML_date
), aDate
);
3215 case RedlineType::Delete
:
3216 m_pSerializer
->startElementNS( XML_w
, XML_del
,
3217 FSNS( XML_w
, XML_id
), aId
,
3218 FSNS( XML_w
, XML_author
), aAuthor
,
3219 FSNS( XML_w
, XML_date
), aDate
);
3222 case RedlineType::Format
:
3223 SAL_INFO("sw.ww8", "TODO DocxAttributeOutput::StartRedline()" );
3230 void DocxAttributeOutput::EndRedline( const SwRedlineData
* pRedlineData
)
3232 if ( !pRedlineData
|| m_bWritingField
)
3235 switch ( pRedlineData
->GetType() )
3237 case RedlineType::Insert
:
3238 m_pSerializer
->endElementNS( XML_w
, XML_ins
);
3241 case RedlineType::Delete
:
3242 m_pSerializer
->endElementNS( XML_w
, XML_del
);
3245 case RedlineType::Format
:
3246 SAL_INFO("sw.ww8", "TODO DocxAttributeOutput::EndRedline()" );
3253 void DocxAttributeOutput::FormatDrop( const SwTextNode
& /*rNode*/, const SwFormatDrop
& /*rSwFormatDrop*/, sal_uInt16
/*nStyle*/, ww8::WW8TableNodeInfo::Pointer_t
/*pTextNodeInfo*/, ww8::WW8TableNodeInfoInner::Pointer_t
)
3255 SAL_INFO("sw.ww8", "TODO DocxAttributeOutput::FormatDrop( const SwTextNode& rNode, const SwFormatDrop& rSwFormatDrop, sal_uInt16 nStyle )" );
3258 void DocxAttributeOutput::ParagraphStyle( sal_uInt16 nStyle
)
3260 OString
aStyleId(m_rExport
.m_pStyles
->GetStyleId(nStyle
));
3262 m_pSerializer
->singleElementNS(XML_w
, XML_pStyle
, FSNS(XML_w
, XML_val
), aStyleId
);
3265 static void impl_borderLine( FSHelperPtr
const & pSerializer
, sal_Int32 elementToken
, const SvxBorderLine
* pBorderLine
, sal_uInt16 nDist
,
3266 bool bWriteShadow
, const table::BorderLine2
* rStyleProps
= nullptr )
3268 // Compute val attribute value
3271 // basicWideOutline, basicWideInline
3272 // OOXml also supports those types of borders, but we'll try to play with the first ones.
3273 // thickThinMediumGap, thickThinLargeGap, thickThinSmallGap
3274 // thinThickLargeGap, thinThickMediumGap, thinThickSmallGap
3275 const char* pVal
= "nil";
3276 if ( pBorderLine
&& !pBorderLine
->isEmpty( ) )
3278 switch (pBorderLine
->GetBorderLineStyle())
3280 case SvxBorderLineStyle::SOLID
:
3283 case SvxBorderLineStyle::DOTTED
:
3286 case SvxBorderLineStyle::DASHED
:
3289 case SvxBorderLineStyle::DOUBLE
:
3290 case SvxBorderLineStyle::DOUBLE_THIN
:
3293 case SvxBorderLineStyle::THINTHICK_SMALLGAP
:
3294 pVal
= "thinThickSmallGap";
3296 case SvxBorderLineStyle::THINTHICK_MEDIUMGAP
:
3297 pVal
= "thinThickMediumGap";
3299 case SvxBorderLineStyle::THINTHICK_LARGEGAP
:
3300 pVal
= "thinThickLargeGap";
3302 case SvxBorderLineStyle::THICKTHIN_SMALLGAP
:
3303 pVal
= "thickThinSmallGap";
3305 case SvxBorderLineStyle::THICKTHIN_MEDIUMGAP
:
3306 pVal
= "thickThinMediumGap";
3308 case SvxBorderLineStyle::THICKTHIN_LARGEGAP
:
3309 pVal
= "thickThinLargeGap";
3311 case SvxBorderLineStyle::EMBOSSED
:
3312 pVal
= "threeDEmboss";
3314 case SvxBorderLineStyle::ENGRAVED
:
3315 pVal
= "threeDEngrave";
3317 case SvxBorderLineStyle::OUTSET
:
3320 case SvxBorderLineStyle::INSET
:
3323 case SvxBorderLineStyle::FINE_DASHED
:
3324 pVal
= "dashSmallGap";
3326 case SvxBorderLineStyle::DASH_DOT
:
3329 case SvxBorderLineStyle::DASH_DOT_DOT
:
3330 pVal
= "dotDotDash";
3332 case SvxBorderLineStyle::NONE
:
3337 else if ( !rStyleProps
|| !rStyleProps
->LineWidth
)
3338 // no line, and no line set by the style either:
3339 // there is no need to write the property
3342 // compare the properties with the theme properties before writing them:
3343 // if they are equal, it means that they were style-defined and there is
3344 // no need to write them.
3345 if( rStyleProps
!= nullptr && pBorderLine
&& !pBorderLine
->isEmpty() &&
3346 pBorderLine
->GetBorderLineStyle() == static_cast<SvxBorderLineStyle
>(rStyleProps
->LineStyle
) &&
3347 pBorderLine
->GetColor() == Color(rStyleProps
->Color
) &&
3348 pBorderLine
->GetWidth() == convertMm100ToTwip( rStyleProps
->LineWidth
) )
3351 FastAttributeList
* pAttr
= FastSerializerHelper::createAttrList();
3352 pAttr
->add( FSNS( XML_w
, XML_val
), OString( pVal
) );
3354 if ( pBorderLine
&& !pBorderLine
->isEmpty() )
3356 // Compute the sz attribute
3358 double const fConverted( ::editeng::ConvertBorderWidthToWord(
3359 pBorderLine
->GetBorderLineStyle(), pBorderLine
->GetWidth()));
3360 // The unit is the 8th of point
3361 sal_Int32 nWidth
= sal_Int32( fConverted
/ 2.5 );
3362 const sal_Int32 nMinWidth
= 2;
3363 const sal_Int32 nMaxWidth
= 96;
3365 if ( nWidth
> nMaxWidth
)
3367 else if ( nWidth
< nMinWidth
)
3370 pAttr
->add( FSNS( XML_w
, XML_sz
), OString::number( nWidth
) );
3372 // Get the distance (in pt)
3373 pAttr
->add(FSNS(XML_w
, XML_space
), OString::number(rtl::math::round(nDist
/ 20.0)));
3375 // Get the color code as an RRGGBB hex value
3376 OString
sColor( msfilter::util::ConvertColor( pBorderLine
->GetColor( ) ) );
3377 pAttr
->add( FSNS( XML_w
, XML_color
), sColor
);
3382 // Set the shadow value
3383 pAttr
->add( FSNS( XML_w
, XML_shadow
), "1" );
3386 XFastAttributeListRef
xAttrs( pAttr
);
3387 pSerializer
->singleElementNS( XML_w
, elementToken
, xAttrs
);
3390 static OutputBorderOptions
lcl_getTableCellBorderOptions(bool bEcma
)
3392 OutputBorderOptions rOptions
;
3394 rOptions
.tag
= XML_tcBorders
;
3395 rOptions
.bUseStartEnd
= !bEcma
;
3396 rOptions
.bWriteTag
= true;
3397 rOptions
.bWriteDistance
= false;
3402 static OutputBorderOptions
lcl_getBoxBorderOptions()
3404 OutputBorderOptions rOptions
;
3406 rOptions
.tag
= XML_pBdr
;
3407 rOptions
.bUseStartEnd
= false;
3408 rOptions
.bWriteTag
= false;
3409 rOptions
.bWriteDistance
= true;
3414 static void impl_borders( FSHelperPtr
const & pSerializer
,
3415 const SvxBoxItem
& rBox
,
3416 const OutputBorderOptions
& rOptions
,
3417 std::map
<SvxBoxItemLine
,
3418 css::table::BorderLine2
> &rTableStyleConf
)
3420 static const SvxBoxItemLine aBorders
[] =
3422 SvxBoxItemLine::TOP
, SvxBoxItemLine::LEFT
, SvxBoxItemLine::BOTTOM
, SvxBoxItemLine::RIGHT
3425 const sal_Int32 aXmlElements
[] =
3428 rOptions
.bUseStartEnd
? XML_start
: XML_left
,
3430 rOptions
.bUseStartEnd
? XML_end
: XML_right
3432 bool tagWritten
= false;
3433 const SvxBoxItemLine
* pBrd
= aBorders
;
3435 for( int i
= 0; i
< 4; ++i
, ++pBrd
)
3437 const SvxBorderLine
* pLn
= rBox
.GetLine( *pBrd
);
3438 const table::BorderLine2
*aStyleProps
= nullptr;
3439 if( rTableStyleConf
.find( *pBrd
) != rTableStyleConf
.end() )
3440 aStyleProps
= &rTableStyleConf
[ *pBrd
];
3442 if (!tagWritten
&& rOptions
.bWriteTag
)
3444 pSerializer
->startElementNS(XML_w
, rOptions
.tag
);
3448 bool bWriteShadow
= false;
3449 if (rOptions
.aShadowLocation
== SvxShadowLocation::NONE
)
3451 // The border has no shadow
3453 else if (rOptions
.aShadowLocation
== SvxShadowLocation::BottomRight
)
3455 // Special case of 'Bottom-Right' shadow:
3456 // If the shadow location is 'Bottom-Right' - then turn on the shadow
3457 // for ALL the sides. This is because in Word - if you select a shadow
3458 // for a border - it turn on the shadow for ALL the sides (but shows only
3459 // the bottom-right one).
3460 // This is so that no information will be lost if passed through LibreOffice
3461 bWriteShadow
= true;
3465 // If there is a shadow, and it's not the regular 'Bottom-Right',
3466 // then write only the 'shadowed' sides of the border
3468 ((rOptions
.aShadowLocation
== SvxShadowLocation::TopLeft
|| rOptions
.aShadowLocation
== SvxShadowLocation::TopRight
) && *pBrd
== SvxBoxItemLine::TOP
) ||
3469 ((rOptions
.aShadowLocation
== SvxShadowLocation::TopLeft
|| rOptions
.aShadowLocation
== SvxShadowLocation::BottomLeft
) && *pBrd
== SvxBoxItemLine::LEFT
) ||
3470 ((rOptions
.aShadowLocation
== SvxShadowLocation::BottomLeft
) && *pBrd
== SvxBoxItemLine::BOTTOM
) ||
3471 ((rOptions
.aShadowLocation
== SvxShadowLocation::TopRight
) && *pBrd
== SvxBoxItemLine::RIGHT
)
3474 bWriteShadow
= true;
3478 sal_uInt16 nDist
= 0;
3479 if (rOptions
.bWriteDistance
)
3481 if (rOptions
.pDistances
)
3483 if ( *pBrd
== SvxBoxItemLine::TOP
)
3484 nDist
= rOptions
.pDistances
->nTop
;
3485 else if ( *pBrd
== SvxBoxItemLine::LEFT
)
3486 nDist
= rOptions
.pDistances
->nLeft
;
3487 else if ( *pBrd
== SvxBoxItemLine::BOTTOM
)
3488 nDist
= rOptions
.pDistances
->nBottom
;
3489 else if ( *pBrd
== SvxBoxItemLine::RIGHT
)
3490 nDist
= rOptions
.pDistances
->nRight
;
3494 nDist
= rBox
.GetDistance(*pBrd
);
3498 impl_borderLine( pSerializer
, aXmlElements
[i
], pLn
, nDist
, bWriteShadow
, aStyleProps
);
3500 if (tagWritten
&& rOptions
.bWriteTag
) {
3501 pSerializer
->endElementNS( XML_w
, rOptions
.tag
);
3505 static void impl_cellMargins( FSHelperPtr
const & pSerializer
, const SvxBoxItem
& rBox
, sal_Int32 tag
, bool bUseStartEnd
, const SvxBoxItem
* pDefaultMargins
= nullptr)
3507 static const SvxBoxItemLine aBorders
[] =
3509 SvxBoxItemLine::TOP
, SvxBoxItemLine::LEFT
, SvxBoxItemLine::BOTTOM
, SvxBoxItemLine::RIGHT
3512 const sal_Int32 aXmlElements
[] =
3515 bUseStartEnd
? XML_start
: XML_left
,
3517 bUseStartEnd
? XML_end
: XML_right
3519 bool tagWritten
= false;
3520 const SvxBoxItemLine
* pBrd
= aBorders
;
3521 for( int i
= 0; i
< 4; ++i
, ++pBrd
)
3523 sal_Int32 nDist
= sal_Int32( rBox
.GetDistance( *pBrd
) );
3525 if (pDefaultMargins
)
3527 // Skip output if cell margin == table default margin
3528 if (sal_Int32( pDefaultMargins
->GetDistance( *pBrd
) ) == nDist
)
3533 pSerializer
->startElementNS(XML_w
, tag
);
3536 pSerializer
->singleElementNS( XML_w
, aXmlElements
[i
],
3537 FSNS( XML_w
, XML_w
), OString::number(nDist
),
3538 FSNS( XML_w
, XML_type
), "dxa" );
3541 pSerializer
->endElementNS( XML_w
, tag
);
3545 void DocxAttributeOutput::TableCellProperties( ww8::WW8TableNodeInfoInner::Pointer_t
const & pTableTextNodeInfoInner
, sal_uInt32 nCell
, sal_uInt32 nRow
)
3547 m_pSerializer
->startElementNS(XML_w
, XML_tcPr
);
3549 const SwTableBox
*pTableBox
= pTableTextNodeInfoInner
->getTableBox( );
3551 bool bEcma
= GetExport().GetFilter().getVersion( ) == oox::core::ECMA_DIALECT
;
3553 // Output any table cell redlines if there are any attached to this specific cell
3554 TableCellRedline( pTableTextNodeInfoInner
);
3556 // Cell preferred width
3557 SwTwips nWidth
= GetGridCols( pTableTextNodeInfoInner
)->at( nCell
);
3559 nWidth
= nWidth
- GetGridCols( pTableTextNodeInfoInner
)->at( nCell
- 1 );
3560 m_pSerializer
->singleElementNS( XML_w
, XML_tcW
,
3561 FSNS( XML_w
, XML_w
), OString::number(nWidth
),
3562 FSNS( XML_w
, XML_type
), "dxa" );
3565 const SwWriteTableRows
& rRows
= m_xTableWrt
->GetRows( );
3566 SwWriteTableRow
*pRow
= rRows
[ nRow
].get();
3567 const SwWriteTableCells
& rTableCells
= pRow
->GetCells();
3568 if (nCell
< rTableCells
.size() )
3570 const SwWriteTableCell
& rCell
= *rTableCells
[nCell
];
3571 const sal_uInt16 nColSpan
= rCell
.GetColSpan();
3573 m_pSerializer
->singleElementNS( XML_w
, XML_gridSpan
,
3574 FSNS( XML_w
, XML_val
), OString::number(nColSpan
) );
3578 ww8::RowSpansPtr xRowSpans
= pTableTextNodeInfoInner
->getRowSpansOfRow();
3579 sal_Int32 vSpan
= (*xRowSpans
)[nCell
];
3582 m_pSerializer
->singleElementNS(XML_w
, XML_vMerge
, FSNS(XML_w
, XML_val
), "restart");
3584 else if ( vSpan
< 0 )
3586 m_pSerializer
->singleElementNS(XML_w
, XML_vMerge
, FSNS(XML_w
, XML_val
), "continue");
3589 if (const SfxGrabBagItem
* pItem
= pTableBox
->GetFrameFormat()->GetAttrSet().GetItem
<SfxGrabBagItem
>(RES_FRMATR_GRABBAG
))
3591 const std::map
<OUString
, uno::Any
>& rGrabBag
= pItem
->GetGrabBag();
3592 std::map
<OUString
, uno::Any
>::const_iterator it
= rGrabBag
.find("CellCnfStyle");
3593 if (it
!= rGrabBag
.end())
3595 uno::Sequence
<beans::PropertyValue
> aAttributes
= it
->second
.get
< uno::Sequence
<beans::PropertyValue
> >();
3596 m_pTableStyleExport
->CnfStyle(aAttributes
);
3601 const SvxBoxItem
& rBox
= pTableBox
->GetFrameFormat( )->GetBox( );
3602 const SvxBoxItem
& rDefaultBox
= (*tableFirstCells
.rbegin())->getTableBox( )->GetFrameFormat( )->GetBox( );
3605 impl_borders(m_pSerializer
, rBox
, lcl_getTableCellBorderOptions(bEcma
),
3606 m_aTableStyleConfs
.back());
3609 TableBackgrounds( pTableTextNodeInfoInner
);
3613 impl_cellMargins( m_pSerializer
, rBox
, XML_tcMar
, !bEcma
, &rDefaultBox
);
3616 TableVerticalCell( pTableTextNodeInfoInner
);
3618 m_pSerializer
->endElementNS( XML_w
, XML_tcPr
);
3621 void DocxAttributeOutput::InitTableHelper( ww8::WW8TableNodeInfoInner::Pointer_t
const & pTableTextNodeInfoInner
)
3623 const SwTable
* pTable
= pTableTextNodeInfoInner
->getTable();
3624 if (m_xTableWrt
&& pTable
== m_xTableWrt
->GetTable())
3627 tools::Long nPageSize
= 0;
3628 bool bRelBoxSize
= false;
3630 // Create the SwWriteTable instance to use col spans (and maybe other infos)
3631 GetTablePageSize( pTableTextNodeInfoInner
.get(), nPageSize
, bRelBoxSize
);
3633 const SwFrameFormat
*pFormat
= pTable
->GetFrameFormat( );
3634 const sal_uInt32 nTableSz
= static_cast<sal_uInt32
>(pFormat
->GetFrameSize( ).GetWidth( ));
3636 const SwHTMLTableLayout
*pLayout
= pTable
->GetHTMLTableLayout();
3637 if( pLayout
&& pLayout
->IsExportable() )
3638 m_xTableWrt
.reset(new SwWriteTable(pTable
, pLayout
));
3640 m_xTableWrt
.reset(new SwWriteTable(pTable
, pTable
->GetTabLines(), nPageSize
, nTableSz
, false));
3643 void DocxAttributeOutput::StartTable( ww8::WW8TableNodeInfoInner::Pointer_t
const & pTableTextNodeInfoInner
)
3645 m_aTableStyleConfs
.push_back({});
3647 // In case any paragraph SDT's are open, close them here.
3650 m_pSerializer
->startElementNS(XML_w
, XML_tbl
);
3652 tableFirstCells
.push_back(pTableTextNodeInfoInner
);
3653 lastOpenCell
.push_back(-1);
3654 lastClosedCell
.push_back(-1);
3656 InitTableHelper( pTableTextNodeInfoInner
);
3657 TableDefinition( pTableTextNodeInfoInner
);
3660 void DocxAttributeOutput::EndTable()
3662 m_pSerializer
->endElementNS( XML_w
, XML_tbl
);
3664 if ( m_tableReference
->m_nTableDepth
> 0 )
3665 --m_tableReference
->m_nTableDepth
;
3667 lastClosedCell
.pop_back();
3668 lastOpenCell
.pop_back();
3669 tableFirstCells
.pop_back();
3671 // We closed the table; if it is a nested table, the cell that contains it
3673 // set to true only if we were in a nested table, not otherwise.
3674 if( !tableFirstCells
.empty() )
3675 m_tableReference
->m_bTableCellOpen
= true;
3677 // Cleans the table helper
3678 m_xTableWrt
.reset();
3680 m_aTableStyleConfs
.pop_back();
3683 void DocxAttributeOutput::StartTableRow( ww8::WW8TableNodeInfoInner::Pointer_t
const & pTableTextNodeInfoInner
)
3685 m_pSerializer
->startElementNS(XML_w
, XML_tr
);
3687 // Output the row properties
3688 m_pSerializer
->startElementNS(XML_w
, XML_trPr
);
3690 // Header row: tblHeader
3691 const SwTable
*pTable
= pTableTextNodeInfoInner
->getTable( );
3692 if ( pTable
->GetRowsToRepeat( ) > pTableTextNodeInfoInner
->getRow( ) )
3693 m_pSerializer
->singleElementNS(XML_w
, XML_tblHeader
, FSNS(XML_w
, XML_val
), "true"); // TODO to overwrite table style may need explicit false
3695 TableRowRedline( pTableTextNodeInfoInner
);
3696 TableHeight( pTableTextNodeInfoInner
);
3697 TableCanSplit( pTableTextNodeInfoInner
);
3699 const SwTableBox
*pTableBox
= pTableTextNodeInfoInner
->getTableBox();
3700 const SwTableLine
* pTableLine
= pTableBox
->GetUpper();
3701 if (const SfxGrabBagItem
* pItem
= pTableLine
->GetFrameFormat()->GetAttrSet().GetItem
<SfxGrabBagItem
>(RES_FRMATR_GRABBAG
))
3703 const std::map
<OUString
, uno::Any
>& rGrabBag
= pItem
->GetGrabBag();
3704 std::map
<OUString
, uno::Any
>::const_iterator it
= rGrabBag
.find("RowCnfStyle");
3705 if (it
!= rGrabBag
.end())
3707 uno::Sequence
<beans::PropertyValue
> aAttributes
= it
->second
.get
< uno::Sequence
<beans::PropertyValue
> >();
3708 m_pTableStyleExport
->CnfStyle(aAttributes
);
3713 m_pSerializer
->endElementNS( XML_w
, XML_trPr
);
3716 void DocxAttributeOutput::EndTableRow( )
3718 m_pSerializer
->endElementNS( XML_w
, XML_tr
);
3719 lastOpenCell
.back() = -1;
3720 lastClosedCell
.back() = -1;
3723 void DocxAttributeOutput::StartTableCell( ww8::WW8TableNodeInfoInner::Pointer_t
const & pTableTextNodeInfoInner
, sal_uInt32 nCell
, sal_uInt32 nRow
)
3725 lastOpenCell
.back() = nCell
;
3727 InitTableHelper( pTableTextNodeInfoInner
);
3729 m_pSerializer
->startElementNS(XML_w
, XML_tc
);
3731 // Write the cell properties here
3732 TableCellProperties( pTableTextNodeInfoInner
, nCell
, nRow
);
3734 m_tableReference
->m_bTableCellOpen
= true;
3737 void DocxAttributeOutput::EndTableCell(sal_uInt32 nCell
)
3739 lastClosedCell
.back() = nCell
;
3740 lastOpenCell
.back() = -1;
3742 if (m_tableReference
->m_bTableCellParaSdtOpen
)
3745 m_pSerializer
->endElementNS( XML_w
, XML_tc
);
3747 m_tableReference
->m_bTableCellOpen
= false;
3748 m_tableReference
->m_bTableCellParaSdtOpen
= false;
3751 void DocxAttributeOutput::TableInfoCell( ww8::WW8TableNodeInfoInner::Pointer_t
/*pTableTextNodeInfoInner*/ )
3755 void DocxAttributeOutput::TableInfoRow( ww8::WW8TableNodeInfoInner::Pointer_t
/*pTableTextNodeInfo*/ )
3762 /// Does the same as comphelper::string::padToLength(), but extends the start, not the end.
3763 OString
lcl_padStartToLength(OString
const & aString
, sal_Int32 nLen
, char cFill
)
3765 if (nLen
> aString
.getLength())
3767 sal_Int32 nDiff
= nLen
- aString
.getLength();
3768 OStringBuffer aBuffer
;
3769 comphelper::string::padToLength(aBuffer
, nDiff
, cFill
);
3770 aBuffer
.append(aString
);
3771 return aBuffer
.makeStringAndClear();
3777 //Keep this function in-sync with the one in writerfilter/.../SettingsTable.cxx
3778 //Since this is not import code, "-1" needs to be handled as the mode that LO will save as.
3779 //To identify how your code should handle a "-1", look in DocxExport::WriteSettings().
3780 sal_Int32
lcl_getWordCompatibilityMode( const SwDoc
& rDoc
)
3782 uno::Reference
< beans::XPropertySet
> xPropSet( rDoc
.GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW
);
3783 uno::Reference
< beans::XPropertySetInfo
> xPropSetInfo
= xPropSet
->getPropertySetInfo();
3785 sal_Int32 nWordCompatibilityMode
= -1;
3786 if ( xPropSetInfo
->hasPropertyByName( UNO_NAME_MISC_OBJ_INTEROPGRABBAG
) )
3788 uno::Sequence
< beans::PropertyValue
> propList
;
3789 xPropSet
->getPropertyValue( UNO_NAME_MISC_OBJ_INTEROPGRABBAG
) >>= propList
;
3791 for ( const auto& rProp
: std::as_const(propList
) )
3793 if ( rProp
.Name
== "CompatSettings" )
3795 css::uno::Sequence
< css::beans::PropertyValue
> aCurrentCompatSettings
;
3796 rProp
.Value
>>= aCurrentCompatSettings
;
3798 for ( const auto& rCurrentCompatSetting
: std::as_const(aCurrentCompatSettings
) )
3800 uno::Sequence
< beans::PropertyValue
> aCompatSetting
;
3801 rCurrentCompatSetting
.Value
>>= aCompatSetting
;
3807 for ( const auto& rPropVal
: std::as_const(aCompatSetting
) )
3809 if ( rPropVal
.Name
== "name" ) rPropVal
.Value
>>= sName
;
3810 if ( rPropVal
.Name
== "uri" ) rPropVal
.Value
>>= sUri
;
3811 if ( rPropVal
.Name
== "val" ) rPropVal
.Value
>>= sVal
;
3814 if ( sName
== "compatibilityMode" && sUri
== "http://schemas.microsoft.com/office/word" )
3816 const sal_Int32 nValidMode
= sVal
.toInt32();
3817 // if repeated, highest mode wins in MS Word. 11 is the first valid mode.
3818 if ( nValidMode
> 10 && nValidMode
> nWordCompatibilityMode
)
3819 nWordCompatibilityMode
= nValidMode
;
3827 // TODO: this is duplicated, better store it in DocxExport member?
3828 if (!rDoc
.getIDocumentSettingAccess().get(DocumentSettingId::ADD_EXT_LEADING
))
3830 if (nWordCompatibilityMode
== -1 || 14 < nWordCompatibilityMode
)
3832 nWordCompatibilityMode
= 14;
3836 return nWordCompatibilityMode
;
3841 void DocxAttributeOutput::TableDefinition( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner
)
3843 bool bEcma
= GetExport().GetFilter().getVersion( ) == oox::core::ECMA_DIALECT
;
3845 // Write the table properties
3846 m_pSerializer
->startElementNS(XML_w
, XML_tblPr
);
3848 static const sal_Int32 aOrder
[] =
3850 FSNS( XML_w
, XML_tblStyle
),
3851 FSNS( XML_w
, XML_tblpPr
),
3852 FSNS( XML_w
, XML_tblOverlap
),
3853 FSNS( XML_w
, XML_bidiVisual
),
3854 FSNS( XML_w
, XML_tblStyleRowBandSize
),
3855 FSNS( XML_w
, XML_tblStyleColBandSize
),
3856 FSNS( XML_w
, XML_tblW
),
3857 FSNS( XML_w
, XML_jc
),
3858 FSNS( XML_w
, XML_tblCellSpacing
),
3859 FSNS( XML_w
, XML_tblInd
),
3860 FSNS( XML_w
, XML_tblBorders
),
3861 FSNS( XML_w
, XML_shd
),
3862 FSNS( XML_w
, XML_tblLayout
),
3863 FSNS( XML_w
, XML_tblCellMar
),
3864 FSNS( XML_w
, XML_tblLook
),
3865 FSNS( XML_w
, XML_tblPrChange
)
3868 // postpone the output so that we can later []
3869 // prepend the properties before the run
3870 m_pSerializer
->mark(Tag_TableDefinition
, comphelper::containerToSequence(aOrder
));
3872 tools::Long nPageSize
= 0;
3873 const char* widthType
= "dxa";
3875 // If actual width of table is relative it should export is as "pct".`
3876 const SwTable
*pTable
= pTableTextNodeInfoInner
->getTable();
3877 SwFrameFormat
*pTableFormat
= pTable
->GetFrameFormat( );
3878 const SwFormatFrameSize
&rSize
= pTableFormat
->GetFrameSize();
3879 int nWidthPercent
= rSize
.GetWidthPercent();
3880 // If we export a floating table: we use the widthPercent of the surrounding frame
3881 const ww8::Frame
* pFloatingTableFrame
= m_rExport
.GetFloatingTableFrame();
3882 if (pFloatingTableFrame
)
3884 const SwFormatFrameSize
&rFrameSize
= pFloatingTableFrame
->GetFrameFormat().GetFrameSize();
3885 nWidthPercent
= rFrameSize
.GetWidthPercent();
3887 uno::Reference
<beans::XPropertySet
> xPropertySet(SwXTextTables::GetObject(*pTable
->GetFrameFormat( )),uno::UNO_QUERY
);
3888 bool isWidthRelative
= false;
3889 xPropertySet
->getPropertyValue("IsWidthRelative") >>= isWidthRelative
;
3894 * As per ECMA Specification : ECMA-376, Second Edition, Part 1 - Fundamentals And Markup Language Reference [ 17.18.90 ST_TableWidth (Table Width Units)]
3895 * http://www.schemacentral.com/sc/ooxml/a-w_type-7.html
3897 * Fiftieths of a Percent :
3898 * http://startbigthinksmall.wordpress.com/2010/01/04/points-inches-and-emus-measuring-units-in-office-open-xml/
3899 * pct Width is in Fiftieths of a Percent
3901 * ex. If the Table width is 50% then
3902 * Width in Fiftieths of a percent is (50 * 50) % or 0.5 * 5000 = 2500pct
3904 nPageSize
= nWidthPercent
* 50 ;
3909 bool bRelBoxSize
= false;
3910 // Create the SwWriteTable instance to use col spans (and maybe other infos)
3911 GetTablePageSize( pTableTextNodeInfoInner
.get(), nPageSize
, bRelBoxSize
);
3916 // Output the table preferred width
3917 m_pSerializer
->singleElementNS( XML_w
, XML_tblW
,
3918 FSNS( XML_w
, XML_w
), OString::number(nPageSize
),
3919 FSNS( XML_w
, XML_type
), widthType
);
3921 // Disable layout autofit, as it does not exist in LibreOffice yet
3922 m_pSerializer
->singleElementNS( XML_w
, XML_tblLayout
,
3923 FSNS( XML_w
, XML_type
), "fixed" );
3925 // Look for the table style property in the table grab bag
3926 std::map
<OUString
, css::uno::Any
> aGrabBag
=
3927 pTableFormat
->GetAttrSet().GetItem
<SfxGrabBagItem
>(RES_FRMATR_GRABBAG
)->GetGrabBag();
3929 // We should clear the TableStyle map. In case of Table inside multiple tables it contains the
3930 // table border style of the previous table.
3931 std::map
<SvxBoxItemLine
, css::table::BorderLine2
>& rTableStyleConf
= m_aTableStyleConfs
.back();
3932 rTableStyleConf
.clear();
3934 // Extract properties from grab bag
3935 for( const auto & rGrabBagElement
: aGrabBag
)
3937 if( rGrabBagElement
.first
== "TableStyleName")
3939 OString sStyleName
= OUStringToOString( rGrabBagElement
.second
.get
<OUString
>(), RTL_TEXTENCODING_UTF8
);
3940 m_pSerializer
->singleElementNS(XML_w
, XML_tblStyle
, FSNS(XML_w
, XML_val
), sStyleName
);
3942 else if( rGrabBagElement
.first
== "TableStyleTopBorder" )
3943 rTableStyleConf
[SvxBoxItemLine::TOP
] = rGrabBagElement
.second
.get
<table::BorderLine2
>();
3944 else if( rGrabBagElement
.first
== "TableStyleBottomBorder" )
3945 rTableStyleConf
[SvxBoxItemLine::BOTTOM
]
3946 = rGrabBagElement
.second
.get
<table::BorderLine2
>();
3947 else if( rGrabBagElement
.first
== "TableStyleLeftBorder" )
3948 rTableStyleConf
[SvxBoxItemLine::LEFT
]
3949 = rGrabBagElement
.second
.get
<table::BorderLine2
>();
3950 else if( rGrabBagElement
.first
== "TableStyleRightBorder" )
3951 rTableStyleConf
[SvxBoxItemLine::RIGHT
]
3952 = rGrabBagElement
.second
.get
<table::BorderLine2
>();
3953 else if (rGrabBagElement
.first
== "TableStyleLook")
3955 FastAttributeList
* pAttributeList
= FastSerializerHelper::createAttrList();
3956 const uno::Sequence
<beans::PropertyValue
> aAttributeList
= rGrabBagElement
.second
.get
< uno::Sequence
<beans::PropertyValue
> >();
3958 for (const auto& rAttribute
: aAttributeList
)
3960 if (rAttribute
.Name
== "val")
3961 pAttributeList
->add(FSNS(XML_w
, XML_val
), lcl_padStartToLength(OString::number(rAttribute
.Value
.get
<sal_Int32
>(), 16), 4, '0'));
3964 static DocxStringTokenMap
const aTokens
[] =
3966 {"firstRow", XML_firstRow
},
3967 {"lastRow", XML_lastRow
},
3968 {"firstColumn", XML_firstColumn
},
3969 {"lastColumn", XML_lastColumn
},
3970 {"noHBand", XML_noHBand
},
3971 {"noVBand", XML_noVBand
},
3975 if (sal_Int32 nToken
= DocxStringGetToken(aTokens
, rAttribute
.Name
))
3976 pAttributeList
->add(FSNS(XML_w
, nToken
), (rAttribute
.Value
.get
<sal_Int32
>() ? "1" : "0"));
3980 XFastAttributeListRef
xAttributeList(pAttributeList
);
3981 m_pSerializer
->singleElementNS(XML_w
, XML_tblLook
, xAttributeList
);
3983 else if (rGrabBagElement
.first
== "TablePosition" )
3985 FastAttributeList
*attrListTablePos
= FastSerializerHelper::createAttrList( );
3986 const uno::Sequence
<beans::PropertyValue
> aTablePosition
= rGrabBagElement
.second
.get
<uno::Sequence
<beans::PropertyValue
> >();
3987 // look for a surrounding frame and take it's position values
3988 const ww8::Frame
* pFrame
= m_rExport
.GetFloatingTableFrame();
3991 // we export the values of the surrounding Frame
3992 OString sOrientation
;
3995 // If tblpXSpec or tblpYSpec are present, we do not write tblpX or tblpY!
3996 OString sTblpXSpec
= convertToOOXMLHoriOrient( pFrame
->GetFrameFormat().GetHoriOrient().GetHoriOrient(), pFrame
->GetFrameFormat().GetHoriOrient().IsPosToggle() );
3997 OString sTblpYSpec
= convertToOOXMLVertOrient( pFrame
->GetFrameFormat().GetVertOrient().GetVertOrient() );
3999 sOrientation
= convertToOOXMLVertOrientRel( pFrame
->GetFrameFormat().GetVertOrient().GetRelationOrient() );
4000 attrListTablePos
->add( FSNS( XML_w
, XML_vertAnchor
), sOrientation
.getStr() );
4002 if( !sTblpYSpec
.isEmpty() )
4003 attrListTablePos
->add( FSNS( XML_w
, XML_tblpYSpec
), sTblpYSpec
.getStr() );
4005 sOrientation
= convertToOOXMLHoriOrientRel( pFrame
->GetFrameFormat().GetHoriOrient().GetRelationOrient() );
4006 attrListTablePos
->add( FSNS( XML_w
, XML_horzAnchor
), sOrientation
.getStr() );
4008 if( !sTblpXSpec
.isEmpty() )
4009 attrListTablePos
->add( FSNS( XML_w
, XML_tblpXSpec
), sTblpXSpec
.getStr() );
4011 nValue
= pFrame
->GetFrameFormat().GetULSpace().GetLower();
4013 attrListTablePos
->add( FSNS( XML_w
, XML_bottomFromText
), OString::number( nValue
) );
4015 nValue
= pFrame
->GetFrameFormat().GetLRSpace().GetLeft();
4017 attrListTablePos
->add( FSNS( XML_w
, XML_leftFromText
), OString::number( nValue
) );
4019 nValue
= pFrame
->GetFrameFormat().GetLRSpace().GetRight();
4021 attrListTablePos
->add( FSNS( XML_w
, XML_rightFromText
), OString::number( nValue
) );
4023 nValue
= pFrame
->GetFrameFormat().GetULSpace().GetUpper();
4025 attrListTablePos
->add( FSNS( XML_w
, XML_topFromText
), OString::number( nValue
) );
4027 if( sTblpXSpec
.isEmpty() ) // do not write tblpX if tblpXSpec is present
4029 nValue
= pFrame
->GetFrameFormat().GetHoriOrient().GetPos();
4030 // we need to revert the additional shift introduced by
4031 // lcl_DecrementHoriOrientPosition() in writerfilter
4032 // 1st: left distance of the table
4033 const SwTableBox
* pTabBox
= pTableTextNodeInfoInner
->getTableBox();
4034 const SwFrameFormat
* pFrameFormat
= pTabBox
->GetFrameFormat();
4035 const SvxBoxItem
& rBox
= pFrameFormat
->GetBox( );
4036 sal_uInt16 nLeftDistance
= rBox
.GetDistance(SvxBoxItemLine::LEFT
);
4037 nValue
+= nLeftDistance
;
4039 // 2nd: if a left border is given, revert the shift by half the width
4040 // from lcl_DecrementHoriOrientPosition() in writerfilter
4041 if (const editeng::SvxBorderLine
* pLeftBorder
= rBox
.GetLeft())
4043 tools::Long nWidth
= pLeftBorder
->GetWidth();
4044 nValue
+= (nWidth
/ 2);
4047 attrListTablePos
->add( FSNS( XML_w
, XML_tblpX
), OString::number( nValue
) );
4050 if( sTblpYSpec
.isEmpty() ) // do not write tblpY if tblpYSpec is present
4052 nValue
= pFrame
->GetFrameFormat().GetVertOrient().GetPos();
4053 attrListTablePos
->add( FSNS( XML_w
, XML_tblpY
), OString::number( nValue
) );
4056 else // ( pFrame = 0 )
4058 // we export the values from the grabBag
4059 for (const auto& rProp
: aTablePosition
)
4061 if (rProp
.Name
== "vertAnchor" && !rProp
.Value
.get
<OUString
>().isEmpty())
4063 OString sOrientation
= OUStringToOString( rProp
.Value
.get
<OUString
>(), RTL_TEXTENCODING_UTF8
);
4064 attrListTablePos
->add( FSNS( XML_w
, XML_vertAnchor
), sOrientation
.getStr() );
4066 else if (rProp
.Name
== "tblpYSpec" && !rProp
.Value
.get
<OUString
>().isEmpty())
4068 OString sOrientation
= OUStringToOString( rProp
.Value
.get
<OUString
>(), RTL_TEXTENCODING_UTF8
);
4069 attrListTablePos
->add( FSNS( XML_w
, XML_tblpYSpec
), sOrientation
.getStr() );
4071 else if (rProp
.Name
== "horzAnchor" && !rProp
.Value
.get
<OUString
>().isEmpty())
4073 OString sOrientation
= OUStringToOString( rProp
.Value
.get
<OUString
>(), RTL_TEXTENCODING_UTF8
);
4074 attrListTablePos
->add( FSNS( XML_w
, XML_horzAnchor
), sOrientation
.getStr() );
4076 else if (rProp
.Name
== "tblpXSpec" && !rProp
.Value
.get
<OUString
>().isEmpty())
4078 OString sOrientation
= OUStringToOString( rProp
.Value
.get
<OUString
>(), RTL_TEXTENCODING_UTF8
);
4079 attrListTablePos
->add( FSNS( XML_w
, XML_tblpXSpec
), sOrientation
.getStr() );
4081 else if (rProp
.Name
== "bottomFromText")
4083 sal_Int32 nValue
= rProp
.Value
.get
<sal_Int32
>();
4084 attrListTablePos
->add( FSNS( XML_w
, XML_bottomFromText
), OString::number( nValue
) );
4086 else if (rProp
.Name
== "leftFromText")
4088 sal_Int32 nValue
= rProp
.Value
.get
<sal_Int32
>();
4089 attrListTablePos
->add( FSNS( XML_w
, XML_leftFromText
), OString::number( nValue
) );
4091 else if (rProp
.Name
== "rightFromText")
4093 sal_Int32 nValue
= rProp
.Value
.get
<sal_Int32
>();
4094 attrListTablePos
->add( FSNS( XML_w
, XML_rightFromText
), OString::number( nValue
) );
4096 else if (rProp
.Name
== "topFromText")
4098 sal_Int32 nValue
= rProp
.Value
.get
<sal_Int32
>();
4099 attrListTablePos
->add( FSNS( XML_w
, XML_topFromText
), OString::number( nValue
) );
4101 else if (rProp
.Name
== "tblpX")
4103 sal_Int32 nValue
= rProp
.Value
.get
<sal_Int32
>();
4104 attrListTablePos
->add( FSNS( XML_w
, XML_tblpX
), OString::number( nValue
) );
4106 else if (rProp
.Name
== "tblpY")
4108 sal_Int32 nValue
= rProp
.Value
.get
<sal_Int32
>();
4109 attrListTablePos
->add( FSNS( XML_w
, XML_tblpY
), OString::number( nValue
) );
4114 XFastAttributeListRef
xAttrListTablePosRef( attrListTablePos
);
4116 m_pSerializer
->singleElementNS( XML_w
, XML_tblpPr
, xAttrListTablePosRef
);
4117 attrListTablePos
= nullptr;
4120 SAL_WARN("sw.ww8", "DocxAttributeOutput::TableDefinition: unhandled property: " << rGrabBagElement
.first
);
4123 // Output the table alignment
4125 sal_Int32 nIndent
= 0;
4126 switch ( pTableFormat
->GetHoriOrient( ).GetHoriOrient( ) )
4128 case text::HoriOrientation::CENTER
:
4131 case text::HoriOrientation::RIGHT
:
4138 case text::HoriOrientation::NONE
:
4139 case text::HoriOrientation::LEFT_AND_WIDTH
:
4145 nIndent
= sal_Int32( pTableFormat
->GetLRSpace().GetLeft() );
4147 // Table indentation has different meaning in Word, depending if the table is nested or not.
4148 // If nested, tblInd is added to parent table's left spacing and defines left edge position
4149 // If not nested, text position of left-most cell must be at absolute X = tblInd
4150 // so, table_spacing + table_spacing_to_content = tblInd
4152 // tdf#106742: since MS Word 2013 (compatibilityMode >= 15), top-level tables are handled the same as nested tables;
4153 // if no compatibilityMode is defined (which now should only happen on a new export to .docx),
4154 // LO uses a higher compatibility than 2010's 14.
4155 sal_Int32 nMode
= lcl_getWordCompatibilityMode( m_rExport
.m_rDoc
);
4157 const SwFrameFormat
* pFrameFormat
= pTableTextNodeInfoInner
->getTableBox()->GetFrameFormat();
4158 if ((0 < nMode
&& nMode
<= 14) && m_tableReference
->m_nTableDepth
== 0)
4159 nIndent
+= pFrameFormat
->GetBox().GetDistance( SvxBoxItemLine::LEFT
);
4162 // adjust for SW considering table to start mid-border instead of nested/2013's left-side-of-border.
4163 nIndent
-= pFrameFormat
->GetBox().CalcLineWidth( SvxBoxItemLine::LEFT
) / 2;
4169 m_pSerializer
->singleElementNS(XML_w
, XML_jc
, FSNS(XML_w
, XML_val
), pJcVal
);
4171 // Output the table background color (although cell value still needs to be specified)
4172 const SvxBrushItem
*pColorProp
= pTableFormat
->GetAttrSet().GetItem
<SvxBrushItem
>(RES_BACKGROUND
);
4173 Color aColor
= pColorProp
? pColorProp
->GetColor() : COL_AUTO
;
4174 if ( aColor
!= COL_AUTO
)
4176 OString sColor
= msfilter::util::ConvertColor( aColor
);
4177 m_pSerializer
->singleElementNS( XML_w
, XML_shd
,
4178 FSNS( XML_w
, XML_fill
), sColor
,
4179 FSNS( XML_w
, XML_val
), "clear" );
4182 // Output the table borders
4183 TableDefaultBorders( pTableTextNodeInfoInner
);
4185 // Output the default cell margins
4186 TableDefaultCellMargins( pTableTextNodeInfoInner
);
4188 TableBidi( pTableTextNodeInfoInner
);
4190 // Table indent (need to get written even if == 0)
4191 m_pSerializer
->singleElementNS( XML_w
, XML_tblInd
,
4192 FSNS( XML_w
, XML_w
), OString::number(nIndent
),
4193 FSNS( XML_w
, XML_type
), "dxa" );
4195 // Merge the marks for the ordered elements
4196 m_pSerializer
->mergeTopMarks(Tag_TableDefinition
);
4198 m_pSerializer
->endElementNS( XML_w
, XML_tblPr
);
4200 // Write the table grid infos
4201 m_pSerializer
->startElementNS(XML_w
, XML_tblGrid
);
4203 ww8::WidthsPtr pColumnWidths
= GetColumnWidths( pTableTextNodeInfoInner
);
4204 for ( auto aColumnWidth
: *pColumnWidths
)
4206 sal_Int32 nWidth
= sal_Int32( aColumnWidth
) - nPrv
;
4207 m_pSerializer
->singleElementNS( XML_w
, XML_gridCol
,
4208 FSNS( XML_w
, XML_w
), OString::number(nWidth
) );
4209 nPrv
= sal_Int32( aColumnWidth
);
4212 m_pSerializer
->endElementNS( XML_w
, XML_tblGrid
);
4215 void DocxAttributeOutput::TableDefaultBorders( ww8::WW8TableNodeInfoInner::Pointer_t
/*pTableTextNodeInfoInner*/ )
4217 // Table defaults should only be created IF m_aTableStyleConf contents haven't come from a table style.
4218 // Previously this function wrote out Cell A1 as the table default, causing problems with no benefit.
4221 void DocxAttributeOutput::TableDefaultCellMargins( ww8::WW8TableNodeInfoInner::Pointer_t
const & pTableTextNodeInfoInner
)
4223 const SwTableBox
* pTabBox
= pTableTextNodeInfoInner
->getTableBox();
4224 const SwFrameFormat
* pFrameFormat
= pTabBox
->GetFrameFormat();
4225 const SvxBoxItem
& rBox
= pFrameFormat
->GetBox( );
4226 const bool bEcma
= GetExport().GetFilter().getVersion( ) == oox::core::ECMA_DIALECT
;
4228 impl_cellMargins(m_pSerializer
, rBox
, XML_tblCellMar
, !bEcma
);
4231 void DocxAttributeOutput::TableBackgrounds( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner
)
4233 const SwTable
*pTable
= pTableTextNodeInfoInner
->getTable();
4234 const SwTableBox
*pTableBox
= pTableTextNodeInfoInner
->getTableBox( );
4235 const SwTableLine
*pTableRow
= pTableBox
->GetUpper();
4236 const SwFrameFormat
*pFormat
= pTableBox
->GetFrameFormat( );
4238 const SvxBrushItem
*pColorProp
= pFormat
->GetAttrSet().GetItem
<SvxBrushItem
>(RES_BACKGROUND
);
4239 Color aColor
= pColorProp
? pColorProp
->GetColor() : COL_AUTO
;
4241 const SwFrameFormat
*pRowFormat
= pTableRow
->GetFrameFormat( );
4242 const SvxBrushItem
*pRowColorProp
= pRowFormat
->GetAttrSet().GetItem
<SvxBrushItem
>(RES_BACKGROUND
);
4243 if ( pRowColorProp
&& aColor
== COL_AUTO
)
4244 aColor
= pRowColorProp
->GetColor();
4246 const SwFrameFormat
*pTableFormat
= pTable
->GetFrameFormat( );
4247 const SvxBrushItem
*pTableColorProp
= pTableFormat
->GetAttrSet().GetItem
<SvxBrushItem
>(RES_BACKGROUND
);
4248 if ( pTableColorProp
&& aColor
== COL_AUTO
)
4249 aColor
= pTableColorProp
->GetColor();
4251 const OString sColor
= msfilter::util::ConvertColor( aColor
);
4253 std::map
<OUString
, css::uno::Any
> aGrabBag
=
4254 pFormat
->GetAttrSet().GetItem
<SfxGrabBagItem
>(RES_FRMATR_GRABBAG
)->GetGrabBag();
4256 OString sOriginalColor
;
4257 std::map
<OUString
, css::uno::Any
>::iterator aGrabBagElement
= aGrabBag
.find("originalColor");
4258 if( aGrabBagElement
!= aGrabBag
.end() )
4259 sOriginalColor
= OUStringToOString( aGrabBagElement
->second
.get
<OUString
>(), RTL_TEXTENCODING_UTF8
);
4261 if ( sOriginalColor
!= sColor
)
4263 // color changed by the user, or no grab bag: write sColor
4264 if ( sColor
!= "auto" )
4266 m_pSerializer
->singleElementNS( XML_w
, XML_shd
,
4267 FSNS( XML_w
, XML_fill
), sColor
,
4268 FSNS( XML_w
, XML_val
), "clear" );
4273 rtl::Reference
<sax_fastparser::FastAttributeList
> pAttrList
;
4275 for( const auto & rGrabBagElement
: aGrabBag
)
4277 if (!rGrabBagElement
.second
.has
<OUString
>())
4280 OString sValue
= OUStringToOString( rGrabBagElement
.second
.get
<OUString
>(), RTL_TEXTENCODING_UTF8
);
4281 if( rGrabBagElement
.first
== "themeFill")
4282 AddToAttrList( pAttrList
, FSNS( XML_w
, XML_themeFill
), sValue
.getStr() );
4283 else if( rGrabBagElement
.first
== "themeFillTint")
4284 AddToAttrList( pAttrList
, FSNS( XML_w
, XML_themeFillTint
), sValue
.getStr() );
4285 else if( rGrabBagElement
.first
== "themeFillShade")
4286 AddToAttrList( pAttrList
, FSNS( XML_w
, XML_themeFillShade
), sValue
.getStr() );
4287 else if( rGrabBagElement
.first
== "fill" )
4288 AddToAttrList( pAttrList
, FSNS( XML_w
, XML_fill
), sValue
.getStr() );
4289 else if( rGrabBagElement
.first
== "themeColor")
4290 AddToAttrList( pAttrList
, FSNS( XML_w
, XML_themeColor
), sValue
.getStr() );
4291 else if( rGrabBagElement
.first
== "themeTint")
4292 AddToAttrList( pAttrList
, FSNS( XML_w
, XML_themeTint
), sValue
.getStr() );
4293 else if( rGrabBagElement
.first
== "themeShade")
4294 AddToAttrList( pAttrList
, FSNS( XML_w
, XML_themeShade
), sValue
.getStr() );
4295 else if( rGrabBagElement
.first
== "color")
4296 AddToAttrList( pAttrList
, FSNS( XML_w
, XML_color
), sValue
.getStr() );
4297 else if( rGrabBagElement
.first
== "val")
4298 AddToAttrList( pAttrList
, FSNS( XML_w
, XML_val
), sValue
.getStr() );
4300 m_pSerializer
->singleElementNS( XML_w
, XML_shd
, pAttrList
.get() );
4304 void DocxAttributeOutput::TableRowRedline( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner
)
4306 const SwTableBox
* pTabBox
= pTableTextNodeInfoInner
->getTableBox();
4307 const SwTableLine
* pTabLine
= pTabBox
->GetUpper();
4309 // search next Redline
4310 const SwExtraRedlineTable
& aExtraRedlineTable
= m_rExport
.m_rDoc
.getIDocumentRedlineAccess().GetExtraRedlineTable();
4311 for(sal_uInt16 nCurRedlinePos
= 0; nCurRedlinePos
< aExtraRedlineTable
.GetSize(); ++nCurRedlinePos
)
4313 SwExtraRedline
* pExtraRedline
= aExtraRedlineTable
.GetRedline(nCurRedlinePos
);
4314 const SwTableRowRedline
* pTableRowRedline
= dynamic_cast<const SwTableRowRedline
*>(pExtraRedline
);
4315 if (pTableRowRedline
&& &pTableRowRedline
->GetTableLine() == pTabLine
)
4317 // Redline for this table row
4318 const SwRedlineData
& aRedlineData
= pTableRowRedline
->GetRedlineData();
4319 RedlineType nRedlineType
= aRedlineData
.GetType();
4320 switch (nRedlineType
)
4322 case RedlineType::TableRowInsert
:
4323 case RedlineType::TableRowDelete
:
4325 OString
aId( OString::number( m_nRedlineId
++ ) );
4326 const OUString
&rAuthor( SW_MOD()->GetRedlineAuthor( aRedlineData
.GetAuthor() ) );
4327 OString
aAuthor( OUStringToOString( rAuthor
, RTL_TEXTENCODING_UTF8
) );
4329 OString
aDate( DateTimeToOString( aRedlineData
.GetTimeStamp() ) );
4331 if (nRedlineType
== RedlineType::TableRowInsert
)
4332 m_pSerializer
->singleElementNS( XML_w
, XML_ins
,
4333 FSNS( XML_w
, XML_id
), aId
,
4334 FSNS( XML_w
, XML_author
), aAuthor
,
4335 FSNS( XML_w
, XML_date
), aDate
);
4336 else if (nRedlineType
== RedlineType::TableRowDelete
)
4337 m_pSerializer
->singleElementNS( XML_w
, XML_del
,
4338 FSNS( XML_w
, XML_id
), aId
,
4339 FSNS( XML_w
, XML_author
), aAuthor
,
4340 FSNS( XML_w
, XML_date
), aDate
);
4349 void DocxAttributeOutput::TableCellRedline( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner
)
4351 const SwTableBox
* pTabBox
= pTableTextNodeInfoInner
->getTableBox();
4353 // search next Redline
4354 const SwExtraRedlineTable
& aExtraRedlineTable
= m_rExport
.m_rDoc
.getIDocumentRedlineAccess().GetExtraRedlineTable();
4355 for(sal_uInt16 nCurRedlinePos
= 0; nCurRedlinePos
< aExtraRedlineTable
.GetSize(); ++nCurRedlinePos
)
4357 SwExtraRedline
* pExtraRedline
= aExtraRedlineTable
.GetRedline(nCurRedlinePos
);
4358 const SwTableCellRedline
* pTableCellRedline
= dynamic_cast<const SwTableCellRedline
*>(pExtraRedline
);
4359 if (pTableCellRedline
&& &pTableCellRedline
->GetTableBox() == pTabBox
)
4361 // Redline for this table cell
4362 const SwRedlineData
& aRedlineData
= pTableCellRedline
->GetRedlineData();
4363 RedlineType nRedlineType
= aRedlineData
.GetType();
4364 switch (nRedlineType
)
4366 case RedlineType::TableCellInsert
:
4367 case RedlineType::TableCellDelete
:
4369 OString
aId( OString::number( m_nRedlineId
++ ) );
4370 const OUString
&rAuthor( SW_MOD()->GetRedlineAuthor( aRedlineData
.GetAuthor() ) );
4371 OString
aAuthor( OUStringToOString( rAuthor
, RTL_TEXTENCODING_UTF8
) );
4373 OString
aDate( DateTimeToOString( aRedlineData
.GetTimeStamp() ) );
4375 if (nRedlineType
== RedlineType::TableCellInsert
)
4376 m_pSerializer
->singleElementNS( XML_w
, XML_cellIns
,
4377 FSNS( XML_w
, XML_id
), aId
,
4378 FSNS( XML_w
, XML_author
), aAuthor
,
4379 FSNS( XML_w
, XML_date
), aDate
);
4380 else if (nRedlineType
== RedlineType::TableCellDelete
)
4381 m_pSerializer
->singleElementNS( XML_w
, XML_cellDel
,
4382 FSNS( XML_w
, XML_id
), aId
,
4383 FSNS( XML_w
, XML_author
), aAuthor
,
4384 FSNS( XML_w
, XML_date
), aDate
);
4393 void DocxAttributeOutput::TableHeight( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner
)
4395 const SwTableBox
* pTabBox
= pTableTextNodeInfoInner
->getTableBox();
4396 const SwTableLine
* pTabLine
= pTabBox
->GetUpper();
4397 const SwFrameFormat
* pLineFormat
= pTabLine
->GetFrameFormat();
4399 const SwFormatFrameSize
& rLSz
= pLineFormat
->GetFrameSize();
4400 if ( !(SwFrameSize::Variable
!= rLSz
.GetHeightSizeType() && rLSz
.GetHeight()) )
4403 sal_Int32 nHeight
= rLSz
.GetHeight();
4404 const char *pRule
= nullptr;
4406 switch ( rLSz
.GetHeightSizeType() )
4408 case SwFrameSize::Fixed
: pRule
= "exact"; break;
4409 case SwFrameSize::Minimum
: pRule
= "atLeast"; break;
4414 m_pSerializer
->singleElementNS( XML_w
, XML_trHeight
,
4415 FSNS( XML_w
, XML_val
), OString::number(nHeight
),
4416 FSNS( XML_w
, XML_hRule
), pRule
);
4419 void DocxAttributeOutput::TableCanSplit( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner
)
4421 const SwTableBox
* pTabBox
= pTableTextNodeInfoInner
->getTableBox();
4422 const SwTableLine
* pTabLine
= pTabBox
->GetUpper();
4423 const SwFrameFormat
* pLineFormat
= pTabLine
->GetFrameFormat();
4425 const SwFormatRowSplit
& rSplittable
= pLineFormat
->GetRowSplit( );
4426 // if rSplittable is true then no need to write <w:cantSplit w:val="false"/>
4427 // as default row prop is allow row to break across page.
4428 if( !rSplittable
.GetValue( ) )
4429 m_pSerializer
->singleElementNS(XML_w
, XML_cantSplit
, FSNS(XML_w
, XML_val
), "true");
4432 void DocxAttributeOutput::TableBidi( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner
)
4434 const SwTable
* pTable
= pTableTextNodeInfoInner
->getTable();
4435 const SwFrameFormat
* pFrameFormat
= pTable
->GetFrameFormat();
4437 if ( m_rExport
.TrueFrameDirection( *pFrameFormat
) == SvxFrameDirection::Horizontal_RL_TB
)
4439 m_pSerializer
->singleElementNS(XML_w
, XML_bidiVisual
, FSNS(XML_w
, XML_val
), "true");
4443 void DocxAttributeOutput::TableVerticalCell( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner
)
4445 const SwTableBox
* pTabBox
= pTableTextNodeInfoInner
->getTableBox();
4446 const SwFrameFormat
*pFrameFormat
= pTabBox
->GetFrameFormat( );
4448 if ( SvxFrameDirection::Vertical_RL_TB
== m_rExport
.TrueFrameDirection( *pFrameFormat
) )
4449 m_pSerializer
->singleElementNS(XML_w
, XML_textDirection
, FSNS(XML_w
, XML_val
), "tbRl");
4450 else if ( SvxFrameDirection::Vertical_LR_BT
== m_rExport
.TrueFrameDirection( *pFrameFormat
) )
4452 m_pSerializer
->singleElementNS(XML_w
, XML_textDirection
, FSNS(XML_w
, XML_val
), "btLr");
4455 const SwWriteTableRows
& rRows
= m_xTableWrt
->GetRows( );
4456 SwWriteTableRow
*pRow
= rRows
[ pTableTextNodeInfoInner
->getRow( ) ].get();
4457 sal_uInt32 nCell
= pTableTextNodeInfoInner
->getCell();
4458 const SwWriteTableCells
& rTableCells
= pRow
->GetCells();
4459 if (nCell
>= rTableCells
.size() )
4462 const SwWriteTableCell
*const pCell
= pRow
->GetCells()[ nCell
].get();
4463 switch( pCell
->GetVertOri())
4465 case text::VertOrientation::TOP
:
4467 case text::VertOrientation::CENTER
:
4468 m_pSerializer
->singleElementNS(XML_w
, XML_vAlign
, FSNS(XML_w
, XML_val
), "center");
4470 case text::VertOrientation::BOTTOM
:
4471 m_pSerializer
->singleElementNS(XML_w
, XML_vAlign
, FSNS(XML_w
, XML_val
), "bottom");
4476 void DocxAttributeOutput::TableNodeInfoInner( ww8::WW8TableNodeInfoInner::Pointer_t pNodeInfoInner
)
4478 // This is called when the nested table ends in a cell, and there's no
4479 // paragraph behind that; so we must check for the ends of cell, rows,
4481 // ['true' to write an empty paragraph, MS Word insists on that]
4482 FinishTableRowCell( pNodeInfoInner
, true );
4485 void DocxAttributeOutput::TableOrientation( ww8::WW8TableNodeInfoInner::Pointer_t
/*pTableTextNodeInfoInner*/ )
4487 SAL_INFO("sw.ww8", "TODO: DocxAttributeOutput::TableOrientation( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )" );
4490 void DocxAttributeOutput::TableSpacing( ww8::WW8TableNodeInfoInner::Pointer_t
/*pTableTextNodeInfoInner*/ )
4492 SAL_INFO("sw.ww8", "TODO: DocxAttributeOutput::TableSpacing( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )" );
4495 void DocxAttributeOutput::TableRowEnd( sal_uInt32
/*nDepth*/ )
4497 SAL_INFO("sw.ww8", "TODO: DocxAttributeOutput::TableRowEnd( sal_uInt32 nDepth = 1 )" );
4500 void DocxAttributeOutput::StartStyles()
4502 m_pSerializer
->startElementNS( XML_w
, XML_styles
,
4503 FSNS( XML_xmlns
, XML_w
), GetExport().GetFilter().getNamespaceURL(OOX_NS(doc
)),
4504 FSNS( XML_xmlns
, XML_w14
), GetExport().GetFilter().getNamespaceURL(OOX_NS(w14
)),
4505 FSNS( XML_xmlns
, XML_mc
), GetExport().GetFilter().getNamespaceURL(OOX_NS(mce
)),
4506 FSNS( XML_mc
, XML_Ignorable
), "w14" );
4512 sal_Int32
DocxStringGetToken(DocxStringTokenMap
const * pMap
, const OUString
& rName
)
4514 OString sName
= OUStringToOString(rName
, RTL_TEXTENCODING_UTF8
);
4515 while (pMap
->pToken
)
4517 if (sName
== pMap
->pToken
)
4518 return pMap
->nToken
;
4527 DocxStringTokenMap
const aDefaultTokens
[] = {
4528 {"defQFormat", XML_defQFormat
},
4529 {"defUnhideWhenUsed", XML_defUnhideWhenUsed
},
4530 {"defSemiHidden", XML_defSemiHidden
},
4531 {"count", XML_count
},
4532 {"defUIPriority", XML_defUIPriority
},
4533 {"defLockedState", XML_defLockedState
},
4537 DocxStringTokenMap
const aExceptionTokens
[] = {
4539 {"locked", XML_locked
},
4540 {"uiPriority", XML_uiPriority
},
4541 {"semiHidden", XML_semiHidden
},
4542 {"unhideWhenUsed", XML_unhideWhenUsed
},
4543 {"qFormat", XML_qFormat
},
4549 void DocxAttributeOutput::LatentStyles()
4551 // Do we have latent styles available?
4552 uno::Reference
<beans::XPropertySet
> xPropertySet(m_rExport
.m_rDoc
.GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW
);
4553 uno::Sequence
<beans::PropertyValue
> aInteropGrabBag
;
4554 xPropertySet
->getPropertyValue("InteropGrabBag") >>= aInteropGrabBag
;
4555 uno::Sequence
<beans::PropertyValue
> aLatentStyles
;
4556 auto pProp
= std::find_if(aInteropGrabBag
.begin(), aInteropGrabBag
.end(),
4557 [](const beans::PropertyValue
& rProp
) { return rProp
.Name
== "latentStyles"; });
4558 if (pProp
!= aInteropGrabBag
.end())
4559 pProp
->Value
>>= aLatentStyles
;
4560 if (!aLatentStyles
.hasElements())
4563 // Extract default attributes first.
4564 sax_fastparser::FastAttributeList
* pAttributeList
= FastSerializerHelper::createAttrList();
4565 uno::Sequence
<beans::PropertyValue
> aLsdExceptions
;
4566 for (const auto& rLatentStyle
: std::as_const(aLatentStyles
))
4568 if (sal_Int32 nToken
= DocxStringGetToken(aDefaultTokens
, rLatentStyle
.Name
))
4569 pAttributeList
->add(FSNS(XML_w
, nToken
), OUStringToOString(rLatentStyle
.Value
.get
<OUString
>(), RTL_TEXTENCODING_UTF8
));
4570 else if (rLatentStyle
.Name
== "lsdExceptions")
4571 rLatentStyle
.Value
>>= aLsdExceptions
;
4574 XFastAttributeListRef
xAttributeList(pAttributeList
);
4575 m_pSerializer
->startElementNS(XML_w
, XML_latentStyles
, xAttributeList
);
4576 pAttributeList
= nullptr;
4578 // Then handle the exceptions.
4579 for (const auto& rLsdException
: std::as_const(aLsdExceptions
))
4581 pAttributeList
= FastSerializerHelper::createAttrList();
4583 uno::Sequence
<beans::PropertyValue
> aAttributes
;
4584 rLsdException
.Value
>>= aAttributes
;
4585 for (const auto& rAttribute
: std::as_const(aAttributes
))
4586 if (sal_Int32 nToken
= DocxStringGetToken(aExceptionTokens
, rAttribute
.Name
))
4587 pAttributeList
->add(FSNS(XML_w
, nToken
), OUStringToOString(rAttribute
.Value
.get
<OUString
>(), RTL_TEXTENCODING_UTF8
));
4589 xAttributeList
= pAttributeList
;
4590 m_pSerializer
->singleElementNS(XML_w
, XML_lsdException
, xAttributeList
);
4591 pAttributeList
= nullptr;
4594 m_pSerializer
->endElementNS(XML_w
, XML_latentStyles
);
4597 void DocxAttributeOutput::OutputDefaultItem(const SfxPoolItem
& rHt
)
4599 bool bMustWrite
= true;
4600 switch (rHt
.Which())
4602 case RES_CHRATR_CASEMAP
:
4603 bMustWrite
= static_cast< const SvxCaseMapItem
& >(rHt
).GetCaseMap() != SvxCaseMap::NotMapped
;
4605 case RES_CHRATR_COLOR
:
4606 bMustWrite
= static_cast< const SvxColorItem
& >(rHt
).GetValue() != COL_AUTO
;
4608 case RES_CHRATR_CONTOUR
:
4609 bMustWrite
= static_cast< const SvxContourItem
& >(rHt
).GetValue();
4611 case RES_CHRATR_CROSSEDOUT
:
4612 bMustWrite
= static_cast< const SvxCrossedOutItem
& >(rHt
).GetStrikeout() != STRIKEOUT_NONE
;
4614 case RES_CHRATR_ESCAPEMENT
:
4615 bMustWrite
= static_cast< const SvxEscapementItem
& >(rHt
).GetEscapement() != SvxEscapement::Off
;
4617 case RES_CHRATR_FONT
:
4620 case RES_CHRATR_FONTSIZE
:
4621 bMustWrite
= static_cast< const SvxFontHeightItem
& >(rHt
).GetHeight() != 200; // see StyleSheetTable_Impl::StyleSheetTable_Impl() where we set this default
4623 case RES_CHRATR_KERNING
:
4624 bMustWrite
= static_cast< const SvxKerningItem
& >(rHt
).GetValue() != 0;
4626 case RES_CHRATR_LANGUAGE
:
4629 case RES_CHRATR_POSTURE
:
4630 bMustWrite
= static_cast< const SvxPostureItem
& >(rHt
).GetPosture() != ITALIC_NONE
;
4632 case RES_CHRATR_SHADOWED
:
4633 bMustWrite
= static_cast< const SvxShadowedItem
& >(rHt
).GetValue();
4635 case RES_CHRATR_UNDERLINE
:
4636 bMustWrite
= static_cast< const SvxUnderlineItem
& >(rHt
).GetLineStyle() != LINESTYLE_NONE
;
4638 case RES_CHRATR_WEIGHT
:
4639 bMustWrite
= static_cast< const SvxWeightItem
& >(rHt
).GetWeight() != WEIGHT_NORMAL
;
4641 case RES_CHRATR_AUTOKERN
:
4642 bMustWrite
= static_cast< const SvxAutoKernItem
& >(rHt
).GetValue();
4644 case RES_CHRATR_BLINK
:
4645 bMustWrite
= static_cast< const SvxBlinkItem
& >(rHt
).GetValue();
4647 case RES_CHRATR_BACKGROUND
:
4649 const SvxBrushItem
& rBrushItem
= static_cast< const SvxBrushItem
& >(rHt
);
4650 bMustWrite
= (rBrushItem
.GetColor() != COL_AUTO
||
4651 rBrushItem
.GetShadingValue() != ShadingPattern::CLEAR
||
4652 rBrushItem
.GetGraphic() != nullptr ||
4653 rBrushItem
.GetGraphicObject() != nullptr);
4657 case RES_CHRATR_CJK_FONT
:
4660 case RES_CHRATR_CJK_FONTSIZE
:
4661 bMustWrite
= false; // we have written it already as RES_CHRATR_FONTSIZE
4663 case RES_CHRATR_CJK_LANGUAGE
:
4666 case RES_CHRATR_CJK_POSTURE
:
4667 bMustWrite
= false; // we have written it already as RES_CHRATR_POSTURE
4669 case RES_CHRATR_CJK_WEIGHT
:
4670 bMustWrite
= false; // we have written it already as RES_CHRATR_WEIGHT
4673 case RES_CHRATR_CTL_FONT
:
4676 case RES_CHRATR_CTL_FONTSIZE
:
4677 bMustWrite
= static_cast< const SvxFontHeightItem
& >(rHt
).GetHeight() != 200; // see StyleSheetTable_Impl::StyleSheetTable_Impl() where we set this default
4679 case RES_CHRATR_CTL_LANGUAGE
:
4682 case RES_CHRATR_CTL_POSTURE
:
4683 bMustWrite
= static_cast< const SvxPostureItem
& >(rHt
).GetPosture() != ITALIC_NONE
;
4685 case RES_CHRATR_CTL_WEIGHT
:
4686 bMustWrite
= static_cast< const SvxWeightItem
& >(rHt
).GetWeight() != WEIGHT_NORMAL
;
4689 case RES_CHRATR_ROTATE
:
4690 bMustWrite
= static_cast< const SvxCharRotateItem
& >(rHt
).GetValue() != Degree10(0);
4692 case RES_CHRATR_EMPHASIS_MARK
:
4693 bMustWrite
= static_cast< const SvxEmphasisMarkItem
& >(rHt
).GetEmphasisMark() != FontEmphasisMark::NONE
;
4695 case RES_CHRATR_TWO_LINES
:
4696 bMustWrite
= static_cast< const SvxTwoLinesItem
& >(rHt
).GetValue();
4698 case RES_CHRATR_SCALEW
:
4699 bMustWrite
= static_cast< const SvxCharScaleWidthItem
& >(rHt
).GetValue() != 100;
4701 case RES_CHRATR_RELIEF
:
4702 bMustWrite
= static_cast< const SvxCharReliefItem
& >(rHt
).GetValue() != FontRelief::NONE
;
4704 case RES_CHRATR_HIDDEN
:
4705 bMustWrite
= static_cast< const SvxCharHiddenItem
& >(rHt
).GetValue();
4707 case RES_CHRATR_BOX
:
4709 const SvxBoxItem
& rBoxItem
= static_cast< const SvxBoxItem
& >(rHt
);
4710 bMustWrite
= rBoxItem
.GetTop() || rBoxItem
.GetLeft() ||
4711 rBoxItem
.GetBottom() || rBoxItem
.GetRight() ||
4712 rBoxItem
.GetSmallestDistance();
4715 case RES_CHRATR_HIGHLIGHT
:
4717 const SvxBrushItem
& rBrushItem
= static_cast< const SvxBrushItem
& >(rHt
);
4718 bMustWrite
= (rBrushItem
.GetColor() != COL_AUTO
||
4719 rBrushItem
.GetShadingValue() != ShadingPattern::CLEAR
||
4720 rBrushItem
.GetGraphic() != nullptr ||
4721 rBrushItem
.GetGraphicObject() != nullptr);
4725 case RES_PARATR_LINESPACING
:
4726 bMustWrite
= static_cast< const SvxLineSpacingItem
& >(rHt
).GetInterLineSpaceRule() != SvxInterLineSpaceRule::Off
;
4728 case RES_PARATR_ADJUST
:
4729 bMustWrite
= static_cast< const SvxAdjustItem
& >(rHt
).GetAdjust() != SvxAdjust::Left
;
4731 case RES_PARATR_SPLIT
:
4732 bMustWrite
= !static_cast< const SvxFormatSplitItem
& >(rHt
).GetValue();
4734 case RES_PARATR_WIDOWS
:
4735 bMustWrite
= static_cast< const SvxWidowsItem
& >(rHt
).GetValue();
4737 case RES_PARATR_TABSTOP
:
4738 bMustWrite
= static_cast< const SvxTabStopItem
& >(rHt
).Count() != 0;
4740 case RES_PARATR_HYPHENZONE
:
4743 case RES_PARATR_NUMRULE
:
4744 bMustWrite
= !static_cast< const SwNumRuleItem
& >(rHt
).GetValue().isEmpty();
4746 case RES_PARATR_SCRIPTSPACE
:
4747 bMustWrite
= !static_cast< const SfxBoolItem
& >(rHt
).GetValue();
4749 case RES_PARATR_HANGINGPUNCTUATION
:
4750 bMustWrite
= !static_cast< const SfxBoolItem
& >(rHt
).GetValue();
4752 case RES_PARATR_FORBIDDEN_RULES
:
4753 bMustWrite
= !static_cast< const SfxBoolItem
& >(rHt
).GetValue();
4755 case RES_PARATR_VERTALIGN
:
4756 bMustWrite
= static_cast< const SvxParaVertAlignItem
& >(rHt
).GetValue() != SvxParaVertAlignItem::Align::Automatic
;
4758 case RES_PARATR_SNAPTOGRID
:
4759 bMustWrite
= !static_cast< const SvxParaGridItem
& >(rHt
).GetValue();
4761 case RES_CHRATR_GRABBAG
:
4766 SAL_INFO("sw.ww8", "Unhandled SfxPoolItem with id " << rHt
.Which() );
4774 void DocxAttributeOutput::DocDefaults( )
4776 // Write the '<w:docDefaults>' section here
4777 m_pSerializer
->startElementNS(XML_w
, XML_docDefaults
);
4779 // Output the default run properties
4780 m_pSerializer
->startElementNS(XML_w
, XML_rPrDefault
);
4782 StartStyleProperties(false, 0);
4784 for (int i
= int(RES_CHRATR_BEGIN
); i
< int(RES_CHRATR_END
); ++i
)
4785 OutputDefaultItem(m_rExport
.m_rDoc
.GetDefault(i
));
4787 EndStyleProperties(false);
4789 m_pSerializer
->endElementNS(XML_w
, XML_rPrDefault
);
4791 // Output the default paragraph properties
4792 m_pSerializer
->startElementNS(XML_w
, XML_pPrDefault
);
4794 StartStyleProperties(true, 0);
4796 for (int i
= int(RES_PARATR_BEGIN
); i
< int(RES_PARATR_END
); ++i
)
4797 OutputDefaultItem(m_rExport
.m_rDoc
.GetDefault(i
));
4799 EndStyleProperties(true);
4801 m_pSerializer
->endElementNS(XML_w
, XML_pPrDefault
);
4803 m_pSerializer
->endElementNS(XML_w
, XML_docDefaults
);
4806 void DocxAttributeOutput::EndStyles( sal_uInt16 nNumberOfStyles
)
4809 // Ms Office seems to have an internal limitation of 4091 styles
4810 // and refuses to load .docx with more, even though the spec seems to allow that;
4811 // so simply if there are more styles, don't export those
4812 const sal_Int32 nCountStylesToWrite
= MSWORD_MAX_STYLES_LIMIT
- nNumberOfStyles
;
4813 m_pTableStyleExport
->TableStyles(nCountStylesToWrite
);
4814 m_pSerializer
->endElementNS( XML_w
, XML_styles
);
4817 void DocxAttributeOutput::DefaultStyle()
4819 // are these the values of enum ww::sti (see ../inc/wwstyles.hxx)?
4820 SAL_INFO("sw.ww8", "TODO DocxAttributeOutput::DefaultStyle()");
4823 /* Writes <a:srcRect> tag back to document.xml if a file contains a cropped image.
4824 * NOTE : Tested on images of type JPEG,EMF/WMF,BMP, PNG and GIF.
4826 void DocxAttributeOutput::WriteSrcRect(
4827 const css::uno::Reference
<css::beans::XPropertySet
>& xShapePropSet
,
4828 const SwFrameFormat
* pFrameFormat
)
4830 uno::Reference
<graphic::XGraphic
> xGraphic
;
4831 xShapePropSet
->getPropertyValue("Graphic") >>= xGraphic
;
4832 const Graphic
aGraphic(xGraphic
);
4834 Size
aOriginalSize(aGraphic
.GetPrefSize());
4836 const MapMode
aMap100mm( MapUnit::Map100thMM
);
4837 const MapMode
& rMapMode
= aGraphic
.GetPrefMapMode();
4838 if (rMapMode
.GetMapUnit() == MapUnit::MapPixel
)
4840 aOriginalSize
= Application::GetDefaultDevice()->PixelToLogic(aOriginalSize
, aMap100mm
);
4843 css::text::GraphicCrop aGraphicCropStruct
;
4844 xShapePropSet
->getPropertyValue("GraphicCrop") >>= aGraphicCropStruct
;
4845 sal_Int32 nCropL
= aGraphicCropStruct
.Left
;
4846 sal_Int32 nCropR
= aGraphicCropStruct
.Right
;
4847 sal_Int32 nCropT
= aGraphicCropStruct
.Top
;
4848 sal_Int32 nCropB
= aGraphicCropStruct
.Bottom
;
4850 // simulate border padding as a negative crop.
4851 const SfxPoolItem
* pItem
;
4852 if (pFrameFormat
&& SfxItemState::SET
== pFrameFormat
->GetItemState(RES_BOX
, false, &pItem
))
4854 const SvxBoxItem
& rBox
= *static_cast<const SvxBoxItem
*>(pItem
);
4855 nCropL
-= rBox
.GetDistance( SvxBoxItemLine::LEFT
);
4856 nCropR
-= rBox
.GetDistance( SvxBoxItemLine::RIGHT
);
4857 nCropT
-= rBox
.GetDistance( SvxBoxItemLine::TOP
);
4858 nCropB
-= rBox
.GetDistance( SvxBoxItemLine::BOTTOM
);
4861 if ( !((0 != nCropL
) || (0 != nCropT
) || (0 != nCropR
) || (0 != nCropB
)) )
4864 double widthMultiplier
= 100000.0/aOriginalSize
.Width();
4865 double heightMultiplier
= 100000.0/aOriginalSize
.Height();
4867 sal_Int32 left
= static_cast<sal_Int32
>(rtl::math::round(nCropL
* widthMultiplier
));
4868 sal_Int32 right
= static_cast<sal_Int32
>(rtl::math::round(nCropR
* widthMultiplier
));
4869 sal_Int32 top
= static_cast<sal_Int32
>(rtl::math::round(nCropT
* heightMultiplier
));
4870 sal_Int32 bottom
= static_cast<sal_Int32
>(rtl::math::round(nCropB
* heightMultiplier
));
4872 m_pSerializer
->singleElementNS( XML_a
, XML_srcRect
,
4873 XML_l
, OString::number(left
),
4874 XML_t
, OString::number(top
),
4875 XML_r
, OString::number(right
),
4876 XML_b
, OString::number(bottom
) );
4879 void DocxAttributeOutput::PopRelIdCache()
4881 if (!m_aRelIdCache
.empty())
4882 m_aRelIdCache
.pop();
4883 if (!m_aSdrRelIdCache
.empty())
4884 m_aSdrRelIdCache
.pop();
4887 void DocxAttributeOutput::PushRelIdCache()
4889 m_aRelIdCache
.emplace();
4890 m_aSdrRelIdCache
.emplace();
4893 OUString
DocxAttributeOutput::FindRelId(BitmapChecksum nChecksum
)
4897 if (!m_aSdrRelIdCache
.empty() && m_aSdrRelIdCache
.top().find(nChecksum
) != m_aSdrRelIdCache
.top().end())
4898 aRet
= m_aSdrRelIdCache
.top()[nChecksum
];
4903 void DocxAttributeOutput::CacheRelId(BitmapChecksum nChecksum
, const OUString
& rRelId
)
4905 if (!m_aSdrRelIdCache
.empty())
4906 m_aSdrRelIdCache
.top()[nChecksum
] = rRelId
;
4909 uno::Reference
<css::text::XTextFrame
> DocxAttributeOutput::GetUnoTextFrame(
4910 css::uno::Reference
<css::drawing::XShape
> xShape
)
4912 return SwTextBoxHelper::getUnoTextFrame(xShape
);
4915 OString
DocxAttributeOutput::getExistingGraphicRelId(BitmapChecksum nChecksum
)
4919 if (m_aRelIdCache
.empty())
4922 auto pIterator
= m_aRelIdCache
.top().find(nChecksum
);
4924 if (pIterator
!= m_aRelIdCache
.top().end())
4926 aResult
= pIterator
->second
;
4932 void DocxAttributeOutput::cacheGraphicRelId(BitmapChecksum nChecksum
, OString
const & rRelId
)
4934 if (!m_aRelIdCache
.empty())
4935 m_aRelIdCache
.top().emplace(nChecksum
, rRelId
);
4938 void DocxAttributeOutput::FlyFrameGraphic( const SwGrfNode
* pGrfNode
, const Size
& rSize
, const SwFlyFrameFormat
* pOLEFrameFormat
, SwOLENode
* pOLENode
, const SdrObject
* pSdrObj
)
4940 SAL_INFO("sw.ww8", "TODO DocxAttributeOutput::FlyFrameGraphic( const SwGrfNode* pGrfNode, const Size& rSize, const SwFlyFrameFormat* pOLEFrameFormat, SwOLENode* pOLENode, const SdrObject* pSdrObj ) - some stuff still missing" );
4942 GetSdtEndBefore(pSdrObj
);
4944 // detect mis-use of the API
4945 assert(pGrfNode
|| (pOLEFrameFormat
&& pOLENode
));
4946 const SwFrameFormat
* pFrameFormat
= pGrfNode
? pGrfNode
->GetFlyFormat() : pOLEFrameFormat
;
4947 // create the relation ID
4949 sal_Int32 nImageType
;
4950 if ( pGrfNode
&& pGrfNode
->IsLinkedFile() )
4952 // linked image, just create the relation
4954 pGrfNode
->GetFileFilterNms( &aFileName
, nullptr );
4956 sal_Int32
const nFragment(aFileName
.indexOf('#'));
4957 sal_Int32
const nForbiddenU(aFileName
.indexOf("%5C"));
4958 sal_Int32
const nForbiddenL(aFileName
.indexOf("%5c"));
4959 if ( (nForbiddenU
!= -1 && (nFragment
== -1 || nForbiddenU
< nFragment
))
4960 || (nForbiddenL
!= -1 && (nFragment
== -1 || nForbiddenL
< nFragment
)))
4962 SAL_WARN("sw.ww8", "DocxAttributeOutput::FlyFrameGraphic: ignoring image with invalid link URL");
4966 // TODO Convert the file name to relative for better interoperability
4968 aRelId
= m_rExport
.AddRelation(
4969 oox::getRelationship(Relationship::IMAGE
),
4972 nImageType
= XML_link
;
4976 // inline, we also have to write the image itself
4979 aGraphic
= pGrfNode
->GetGrf();
4981 aGraphic
= *pOLENode
->GetGraphic();
4983 BitmapChecksum aChecksum
= aGraphic
.GetChecksum();
4984 aRelId
= getExistingGraphicRelId(aChecksum
);
4986 if (aRelId
.isEmpty())
4988 // Not in cache, then need to write it.
4989 m_rDrawingML
.SetFS( m_pSerializer
); // to be sure that we write to the right stream
4991 OUString aImageId
= m_rDrawingML
.WriteImage(aGraphic
);
4993 aRelId
= OUStringToOString( aImageId
, RTL_TEXTENCODING_UTF8
);
4994 cacheGraphicRelId(aChecksum
, aRelId
);
4997 nImageType
= XML_embed
;
5000 // In case there are any grab-bag items on the graphic frame, emit them now.
5001 // These are always character grab-bags, as graphics are at-char or as-char in Word.
5002 const SfxPoolItem
* pItem
= nullptr;
5003 if (pFrameFormat
->GetAttrSet().HasItem(RES_FRMATR_GRABBAG
, &pItem
))
5005 const SfxGrabBagItem
* pGrabBag
= static_cast<const SfxGrabBagItem
*>(pItem
);
5006 CharGrabBag(*pGrabBag
);
5009 rtl::Reference
<sax_fastparser::FastAttributeList
> xFrameAttributes(
5010 FastSerializerHelper::createAttrList());
5013 const SwAttrSet
& rSet
= pGrfNode
->GetSwAttrSet();
5014 MirrorGraph eMirror
= rSet
.Get(RES_GRFATR_MIRRORGRF
).GetValue();
5015 if (eMirror
== MirrorGraph::Vertical
|| eMirror
== MirrorGraph::Both
)
5016 // Mirror on the vertical axis is a horizontal flip.
5017 xFrameAttributes
->add(XML_flipH
, "1");
5018 // RES_GRFATR_ROTATION is sal_uInt16; use sal_uInt32 for multiplication later
5019 if (sal_uInt32 nRot
= rSet
.Get(RES_GRFATR_ROTATION
).GetValue())
5021 // RES_GRFATR_ROTATION is in 10ths of degree; convert to 100ths for macro
5022 sal_uInt32 mOOXMLRot
= oox::drawingml::ExportRotateClockwisify(nRot
*10);
5023 xFrameAttributes
->add(XML_rot
, OString::number(mOOXMLRot
));
5027 css::uno::Reference
<css::beans::XPropertySet
> xShapePropSet
;
5030 css::uno::Reference
<css::drawing::XShape
> xShape(
5031 const_cast<SdrObject
*>(pSdrObj
)->getUnoShape(), css::uno::UNO_QUERY
);
5032 xShapePropSet
.set(xShape
, css::uno::UNO_QUERY
);
5033 assert(xShapePropSet
);
5037 // We need the original (cropped, but unrotated) size of object. So prefer the object data,
5038 // and only use passed frame size as fallback.
5041 if (css::awt::Size val
; xShapePropSet
->getPropertyValue("Size") >>= val
)
5042 aSize
= Size(convertMm100ToTwip(val
.Width
), convertMm100ToTwip(val
.Height
));
5045 m_rExport
.SdrExporter().startDMLAnchorInline(pFrameFormat
, aSize
);
5047 // picture description (used for pic:cNvPr later too)
5048 ::sax_fastparser::FastAttributeList
* docPrattrList
= FastSerializerHelper::createAttrList();
5049 docPrattrList
->add( XML_id
, OString::number( m_anchorId
++).getStr());
5050 docPrattrList
->add( XML_name
, OUStringToOString( pFrameFormat
->GetName(), RTL_TEXTENCODING_UTF8
) );
5051 docPrattrList
->add( XML_descr
, OUStringToOString( pGrfNode
? pGrfNode
->GetDescription() : pOLEFrameFormat
->GetObjDescription(), RTL_TEXTENCODING_UTF8
).getStr());
5052 if( GetExport().GetFilter().getVersion( ) != oox::core::ECMA_DIALECT
)
5053 docPrattrList
->add( XML_title
, OUStringToOString( pGrfNode
? pGrfNode
->GetTitle() : pOLEFrameFormat
->GetObjTitle(), RTL_TEXTENCODING_UTF8
).getStr());
5054 XFastAttributeListRef
docPrAttrListRef( docPrattrList
);
5055 m_pSerializer
->startElementNS( XML_wp
, XML_docPr
, docPrAttrListRef
);
5057 OUString sURL
, sRelId
;
5060 xShapePropSet
->getPropertyValue("HyperLinkURL") >>= sURL
;
5063 if (sURL
.startsWith("#") && sURL
.indexOf(' ') != -1 && !sURL
.endsWith("|outline") && !sURL
.endsWith("|table") &&
5064 !sURL
.endsWith("|frame") && !sURL
.endsWith("|graphic") && !sURL
.endsWith("|ole") && !sURL
.endsWith("|region"))
5066 // Spaces are prohibited in bookmark name.
5067 sURL
= sURL
.replace(' ', '_');
5069 sRelId
= GetExport().GetFilter().addRelation( m_pSerializer
->getOutputStream(),
5070 oox::getRelationship(Relationship::HYPERLINK
),
5071 sURL
, !sURL
.startsWith("#") );
5072 m_pSerializer
->singleElementNS( XML_a
, XML_hlinkClick
,
5073 FSNS( XML_xmlns
, XML_a
), "http://schemas.openxmlformats.org/drawingml/2006/main",
5074 FSNS( XML_r
, XML_id
), sRelId
);
5078 m_pSerializer
->endElementNS( XML_wp
, XML_docPr
);
5080 m_pSerializer
->startElementNS(XML_wp
, XML_cNvGraphicFramePr
);
5081 // TODO change aspect?
5082 m_pSerializer
->singleElementNS( XML_a
, XML_graphicFrameLocks
,
5083 FSNS( XML_xmlns
, XML_a
), GetExport().GetFilter().getNamespaceURL(OOX_NS(dml
)),
5084 XML_noChangeAspect
, "1" );
5085 m_pSerializer
->endElementNS( XML_wp
, XML_cNvGraphicFramePr
);
5087 m_pSerializer
->startElementNS( XML_a
, XML_graphic
,
5088 FSNS( XML_xmlns
, XML_a
), GetExport().GetFilter().getNamespaceURL(OOX_NS(dml
)) );
5089 m_pSerializer
->startElementNS( XML_a
, XML_graphicData
,
5090 XML_uri
, "http://schemas.openxmlformats.org/drawingml/2006/picture" );
5092 m_pSerializer
->startElementNS( XML_pic
, XML_pic
,
5093 FSNS( XML_xmlns
, XML_pic
), GetExport().GetFilter().getNamespaceURL(OOX_NS(dmlPicture
)) );
5095 m_pSerializer
->startElementNS(XML_pic
, XML_nvPicPr
);
5096 // It seems pic:cNvpr and wp:docPr are pretty much the same thing with the same attributes
5097 m_pSerializer
->startElementNS(XML_pic
, XML_cNvPr
, docPrAttrListRef
);
5100 m_pSerializer
->singleElementNS(XML_a
, XML_hlinkClick
, FSNS(XML_r
, XML_id
), sRelId
);
5102 m_pSerializer
->endElementNS( XML_pic
, XML_cNvPr
);
5104 m_pSerializer
->startElementNS(XML_pic
, XML_cNvPicPr
);
5105 // TODO change aspect?
5106 m_pSerializer
->singleElementNS( XML_a
, XML_picLocks
,
5107 XML_noChangeAspect
, "1", XML_noChangeArrowheads
, "1" );
5108 m_pSerializer
->endElementNS( XML_pic
, XML_cNvPicPr
);
5109 m_pSerializer
->endElementNS( XML_pic
, XML_nvPicPr
);
5111 // the actual picture
5112 m_pSerializer
->startElementNS(XML_pic
, XML_blipFill
);
5114 /* At this point we are certain that, WriteImage returns empty RelId
5115 for unhandled graphic type. Therefore we write the picture description
5116 and not the relation( coz there ain't any), so that the user knows
5117 there is an image/graphic in the doc but it is broken instead of
5118 completely discarding it.
5120 if ( aRelId
.isEmpty() )
5121 m_pSerializer
->startElementNS(XML_a
, XML_blip
);
5123 m_pSerializer
->startElementNS(XML_a
, XML_blip
, FSNS(XML_r
, nImageType
), aRelId
);
5127 if ( pGrfNode
&& SfxItemState::SET
== pGrfNode
->GetSwAttrSet().GetItemState(RES_GRFATR_DRAWMODE
, true, &pItem
))
5129 GraphicDrawMode nMode
= static_cast<GraphicDrawMode
>(static_cast<const SfxEnumItemInterface
*>(pItem
)->GetEnumValue());
5130 if (nMode
== GraphicDrawMode::Greys
)
5131 m_pSerializer
->singleElementNS (XML_a
, XML_grayscl
);
5132 else if (nMode
== GraphicDrawMode::Mono
) //black/white has a 0,5 threshold in LibreOffice
5133 m_pSerializer
->singleElementNS (XML_a
, XML_biLevel
, XML_thresh
, OString::number(50000));
5134 else if (nMode
== GraphicDrawMode::Watermark
) //watermark has a brightness/luminance of 0,5 and contrast of -0.7 in LibreOffice
5135 m_pSerializer
->singleElementNS( XML_a
, XML_lum
, XML_bright
, OString::number(70000), XML_contrast
, OString::number(-70000) );
5137 m_pSerializer
->endElementNS( XML_a
, XML_blip
);
5140 WriteSrcRect(xShapePropSet
, pFrameFormat
);
5142 m_pSerializer
->startElementNS(XML_a
, XML_stretch
);
5143 m_pSerializer
->singleElementNS(XML_a
, XML_fillRect
);
5144 m_pSerializer
->endElementNS( XML_a
, XML_stretch
);
5145 m_pSerializer
->endElementNS( XML_pic
, XML_blipFill
);
5147 // TODO setup the right values below
5148 m_pSerializer
->startElementNS(XML_pic
, XML_spPr
, XML_bwMode
, "auto");
5150 m_pSerializer
->startElementNS(
5151 XML_a
, XML_xfrm
, uno::Reference
<xml::sax::XFastAttributeList
>(xFrameAttributes
.get()));
5153 m_pSerializer
->singleElementNS(XML_a
, XML_off
, XML_x
, "0", XML_y
, "0");
5154 OString
aWidth( OString::number( TwipsToEMU( aSize
.Width() ) ) );
5155 OString
aHeight( OString::number( TwipsToEMU( aSize
.Height() ) ) );
5156 m_pSerializer
->singleElementNS(XML_a
, XML_ext
, XML_cx
, aWidth
, XML_cy
, aHeight
);
5157 m_pSerializer
->endElementNS( XML_a
, XML_xfrm
);
5158 m_pSerializer
->startElementNS(XML_a
, XML_prstGeom
, XML_prst
, "rect");
5159 m_pSerializer
->singleElementNS(XML_a
, XML_avLst
);
5160 m_pSerializer
->endElementNS( XML_a
, XML_prstGeom
);
5162 const SvxBoxItem
& rBoxItem
= pFrameFormat
->GetBox();
5163 const SvxBorderLine
* pLeft
= rBoxItem
.GetLine(SvxBoxItemLine::LEFT
);
5164 const SvxBorderLine
* pRight
= rBoxItem
.GetLine(SvxBoxItemLine::RIGHT
);
5165 const SvxBorderLine
* pTop
= rBoxItem
.GetLine(SvxBoxItemLine::TOP
);
5166 const SvxBorderLine
* pBottom
= rBoxItem
.GetLine(SvxBoxItemLine::BOTTOM
);
5167 if (pLeft
|| pRight
|| pTop
|| pBottom
)
5168 m_rExport
.SdrExporter().writeBoxItemLine(rBoxItem
);
5170 m_rExport
.SdrExporter().writeDMLEffectLst(*pFrameFormat
);
5172 m_pSerializer
->endElementNS( XML_pic
, XML_spPr
);
5174 m_pSerializer
->endElementNS( XML_pic
, XML_pic
);
5176 m_pSerializer
->endElementNS( XML_a
, XML_graphicData
);
5177 m_pSerializer
->endElementNS( XML_a
, XML_graphic
);
5178 m_rExport
.SdrExporter().endDMLAnchorInline(pFrameFormat
);
5181 void DocxAttributeOutput::WriteOLE2Obj( const SdrObject
* pSdrObj
, SwOLENode
& rOLENode
, const Size
& rSize
, const SwFlyFrameFormat
* pFlyFrameFormat
, const sal_Int8 nFormulaAlignment
)
5183 if( WriteOLEChart( pSdrObj
, rSize
, pFlyFrameFormat
))
5185 if( WriteOLEMath( rOLENode
, nFormulaAlignment
))
5187 PostponeOLE( rOLENode
, rSize
, pFlyFrameFormat
);
5190 bool DocxAttributeOutput::WriteOLEChart( const SdrObject
* pSdrObj
, const Size
& rSize
, const SwFlyFrameFormat
* pFlyFrameFormat
)
5192 uno::Reference
< drawing::XShape
> xShape( const_cast<SdrObject
*>(pSdrObj
)->getUnoShape(), uno::UNO_QUERY
);
5196 uno::Reference
<beans::XPropertySet
> const xPropSet(xShape
, uno::UNO_QUERY
);
5200 OUString clsid
; // why is the property of type string, not sequence<byte>?
5201 xPropSet
->getPropertyValue("CLSID") >>= clsid
;
5202 assert(!clsid
.isEmpty());
5203 SvGlobalName aClassID
;
5204 bool const isValid(aClassID
.MakeId(clsid
));
5205 assert(isValid
); (void)isValid
;
5207 if (!SotExchange::IsChart(aClassID
))
5210 m_aPostponedCharts
.push_back(PostponedChart(pSdrObj
, rSize
, pFlyFrameFormat
));
5215 * Write chart hierarchy in w:drawing after end element of w:rPr tag.
5217 void DocxAttributeOutput::WritePostponedChart()
5219 if (m_aPostponedCharts
.empty())
5222 for (const PostponedChart
& rChart
: m_aPostponedCharts
)
5224 uno::Reference
< chart2::XChartDocument
> xChartDoc
;
5225 uno::Reference
< drawing::XShape
> xShape(const_cast<SdrObject
*>(rChart
.object
)->getUnoShape(), uno::UNO_QUERY
);
5228 uno::Reference
< beans::XPropertySet
> xPropSet( xShape
, uno::UNO_QUERY
);
5230 xChartDoc
.set( xPropSet
->getPropertyValue( "Model" ), uno::UNO_QUERY
);
5233 if( xChartDoc
.is() )
5235 SAL_INFO("sw.ww8", "DocxAttributeOutput::WriteOLE2Obj: export chart ");
5237 m_rExport
.SdrExporter().startDMLAnchorInline(rChart
.frame
, rChart
.size
);
5239 OUString
sName("Object 1");
5240 uno::Reference
< container::XNamed
> xNamed( xShape
, uno::UNO_QUERY
);
5242 sName
= xNamed
->getName();
5244 /* If there is a scenario where a chart is followed by a shape
5245 which is being exported as an alternate content then, the
5246 docPr Id is being repeated, ECMA 20.4.2.5 says that the
5247 docPr Id should be unique, ensuring the same here.
5249 m_pSerializer
->singleElementNS( XML_wp
, XML_docPr
,
5250 XML_id
, OString::number(m_anchorId
++),
5253 m_pSerializer
->singleElementNS(XML_wp
, XML_cNvGraphicFramePr
);
5255 m_pSerializer
->startElementNS( XML_a
, XML_graphic
,
5256 FSNS( XML_xmlns
, XML_a
), GetExport().GetFilter().getNamespaceURL(OOX_NS(dml
)) );
5258 m_pSerializer
->startElementNS( XML_a
, XML_graphicData
,
5259 XML_uri
, "http://schemas.openxmlformats.org/drawingml/2006/chart" );
5263 aRelId
= m_rExport
.OutputChart( xChartDoc
, m_nChartCount
, m_pSerializer
);
5265 m_pSerializer
->singleElementNS( XML_c
, XML_chart
,
5266 FSNS( XML_xmlns
, XML_c
), GetExport().GetFilter().getNamespaceURL(OOX_NS(dmlChart
)),
5267 FSNS( XML_xmlns
, XML_r
), GetExport().GetFilter().getNamespaceURL(OOX_NS(officeRel
)),
5268 FSNS( XML_r
, XML_id
), aRelId
);
5270 m_pSerializer
->endElementNS( XML_a
, XML_graphicData
);
5271 m_pSerializer
->endElementNS( XML_a
, XML_graphic
);
5273 m_rExport
.SdrExporter().endDMLAnchorInline(rChart
.frame
);
5277 m_aPostponedCharts
.clear();
5280 bool DocxAttributeOutput::WriteOLEMath( const SwOLENode
& rOLENode
,const sal_Int8 nAlign
)
5282 uno::Reference
< embed::XEmbeddedObject
> xObj(const_cast<SwOLENode
&>(rOLENode
).GetOLEObj().GetOleRef());
5283 SvGlobalName
aObjName(xObj
->getClassID());
5285 if( !SotExchange::IsMath(aObjName
) )
5290 PostponedMathObjects aPostponedMathObject
;
5291 aPostponedMathObject
.pMathObject
= const_cast<SwOLENode
*>( &rOLENode
);
5292 aPostponedMathObject
.nMathObjAlignment
= nAlign
;
5293 m_aPostponedMaths
.push_back(aPostponedMathObject
);
5295 catch (const uno::Exception
&)
5301 void DocxAttributeOutput::WritePostponedMath(const SwOLENode
* pPostponedMath
, sal_Int8 nAlign
)
5303 uno::Reference
< embed::XEmbeddedObject
> xObj(const_cast<SwOLENode
*>(pPostponedMath
)->GetOLEObj().GetOleRef());
5304 if (embed::EmbedStates::LOADED
== xObj
->getCurrentState())
5306 // must be running so there is a Component
5309 xObj
->changeState(embed::EmbedStates::RUNNING
);
5311 catch (const uno::Exception
&)
5315 uno::Reference
< uno::XInterface
> xInterface( xObj
->getComponent(), uno::UNO_QUERY
);
5316 if (!xInterface
.is())
5318 SAL_WARN("sw.ww8", "Broken math object");
5321 // gcc4.4 (and 4.3 and possibly older) have a problem with dynamic_cast directly to the target class,
5322 // so help it with an intermediate cast. I'm not sure what exactly the problem is, seems to be unrelated
5323 // to RTLD_GLOBAL, so most probably a gcc bug.
5324 oox::FormulaExportBase
* formulaexport
= dynamic_cast<oox::FormulaExportBase
*>(dynamic_cast<SfxBaseModel
*>(xInterface
.get()));
5325 assert( formulaexport
!= nullptr );
5327 formulaexport
->writeFormulaOoxml( m_pSerializer
, GetExport().GetFilter().getVersion(),
5328 oox::drawingml::DOCUMENT_DOCX
, nAlign
);
5331 void DocxAttributeOutput::WritePostponedFormControl(const SdrObject
* pObject
)
5333 if (!pObject
|| pObject
->GetObjInventor() != SdrInventor::FmForm
)
5336 SdrUnoObj
*pFormObj
= const_cast<SdrUnoObj
*>(dynamic_cast< const SdrUnoObj
*>(pObject
));
5340 uno::Reference
<awt::XControlModel
> xControlModel
= pFormObj
->GetUnoControlModel();
5341 uno::Reference
<lang::XServiceInfo
> xInfo(xControlModel
, uno::UNO_QUERY
);
5345 if (xInfo
->supportsService("com.sun.star.form.component.DateField"))
5347 // gather component properties
5349 OUString sDateFormat
;
5350 uno::Reference
<beans::XPropertySet
> xPropertySet(xControlModel
, uno::UNO_QUERY
);
5353 OUString aContentText
;
5354 bool bHasDate
= false;
5355 css::util::Date aUNODate
;
5356 if (xPropertySet
->getPropertyValue("Date") >>= aUNODate
)
5359 Date
aDate(aUNODate
.Day
, aUNODate
.Month
, aUNODate
.Year
);
5360 sDate
= DateToOString(aDate
);
5361 aContentText
= OUString::createFromAscii(DateToDDMMYYYYOString(aDate
).getStr());
5362 sDateFormat
= "dd/MM/yyyy";
5366 aContentText
= xPropertySet
->getPropertyValue("HelpText").get
<OUString
>();
5367 if(sDateFormat
.isEmpty())
5368 sDateFormat
= "dd/MM/yyyy"; // Need to set date format even if there is no date set
5373 m_pSerializer
->startElementNS(XML_w
, XML_sdt
);
5374 m_pSerializer
->startElementNS(XML_w
, XML_sdtPr
);
5377 m_pSerializer
->startElementNS(XML_w
, XML_date
, FSNS(XML_w
, XML_fullDate
), sDate
);
5379 m_pSerializer
->startElementNS(XML_w
, XML_date
);
5381 m_pSerializer
->singleElementNS(XML_w
, XML_dateFormat
, FSNS(XML_w
, XML_val
), sDateFormat
);
5382 m_pSerializer
->singleElementNS(XML_w
, XML_lid
,
5383 FSNS(XML_w
, XML_val
), "en-US");
5384 m_pSerializer
->singleElementNS(XML_w
, XML_storeMappedDataAs
,
5385 FSNS(XML_w
, XML_val
), "dateTime");
5386 m_pSerializer
->singleElementNS(XML_w
, XML_calendar
,
5387 FSNS(XML_w
, XML_val
), "gregorian");
5389 m_pSerializer
->endElementNS(XML_w
, XML_date
);
5390 m_pSerializer
->endElementNS(XML_w
, XML_sdtPr
);
5392 m_pSerializer
->startElementNS(XML_w
, XML_sdtContent
);
5393 m_pSerializer
->startElementNS(XML_w
, XML_r
);
5395 RunText(aContentText
);
5396 m_pSerializer
->endElementNS(XML_w
, XML_r
);
5397 m_pSerializer
->endElementNS(XML_w
, XML_sdtContent
);
5399 m_pSerializer
->endElementNS(XML_w
, XML_sdt
);
5401 else if (xInfo
->supportsService("com.sun.star.form.component.ComboBox"))
5403 // gather component properties
5405 uno::Reference
<beans::XPropertySet
> xPropertySet(xControlModel
, uno::UNO_QUERY
);
5406 OUString sText
= xPropertySet
->getPropertyValue("Text").get
<OUString
>();
5407 const uno::Sequence
<OUString
> aItems
= xPropertySet
->getPropertyValue("StringItemList").get
< uno::Sequence
<OUString
> >();
5411 m_pSerializer
->startElementNS(XML_w
, XML_sdt
);
5412 m_pSerializer
->startElementNS(XML_w
, XML_sdtPr
);
5414 m_pSerializer
->startElementNS(XML_w
, XML_dropDownList
);
5416 for (const auto& rItem
: aItems
)
5418 m_pSerializer
->singleElementNS(XML_w
, XML_listItem
,
5419 FSNS(XML_w
, XML_displayText
), rItem
,
5420 FSNS(XML_w
, XML_value
), rItem
);
5423 m_pSerializer
->endElementNS(XML_w
, XML_dropDownList
);
5424 m_pSerializer
->endElementNS(XML_w
, XML_sdtPr
);
5426 m_pSerializer
->startElementNS(XML_w
, XML_sdtContent
);
5427 m_pSerializer
->startElementNS(XML_w
, XML_r
);
5429 m_pSerializer
->endElementNS(XML_w
, XML_r
);
5430 m_pSerializer
->endElementNS(XML_w
, XML_sdtContent
);
5432 m_pSerializer
->endElementNS(XML_w
, XML_sdt
);
5436 void DocxAttributeOutput::WritePostponedActiveXControl(bool bInsideRun
)
5438 for( const auto & rPostponedDrawing
: m_aPostponedActiveXControls
)
5440 WriteActiveXControl(rPostponedDrawing
.object
, *rPostponedDrawing
.frame
, bInsideRun
);
5442 m_aPostponedActiveXControls
.clear();
5446 void DocxAttributeOutput::WriteActiveXControl(const SdrObject
* pObject
, const SwFrameFormat
& rFrameFormat
, bool bInsideRun
)
5448 SdrUnoObj
*pFormObj
= const_cast<SdrUnoObj
*>(dynamic_cast< const SdrUnoObj
*>(pObject
));
5452 uno::Reference
<awt::XControlModel
> xControlModel
= pFormObj
->GetUnoControlModel();
5453 if (!xControlModel
.is())
5456 const bool bAnchoredInline
= rFrameFormat
.GetAnchor().GetAnchorId() == static_cast<RndStdIds
>(css::text::TextContentAnchorType_AS_CHARACTER
);
5460 m_pSerializer
->startElementNS(XML_w
, XML_r
);
5463 // w:pict for floating embedded control and w:object for inline embedded control
5465 m_pSerializer
->startElementNS(XML_w
, XML_object
);
5467 m_pSerializer
->startElementNS(XML_w
, XML_pict
);
5469 // write ActiveX fragment and ActiveX binary
5470 uno::Reference
<drawing::XShape
> xShape(const_cast<SdrObject
*>(pObject
)->getUnoShape(), uno::UNO_QUERY
);
5471 std::pair
<OString
,OString
> sRelIdAndName
= m_rExport
.WriteActiveXObject(xShape
, xControlModel
);
5473 // VML shape definition
5474 m_rExport
.VMLExporter().SetSkipwzName(true);
5475 m_rExport
.VMLExporter().SetHashMarkForType(true);
5476 m_rExport
.VMLExporter().OverrideShapeIDGen(true, "control_shape_");
5480 sShapeId
= m_rExport
.VMLExporter().AddInlineSdrObject(*pObject
, true);
5484 const SwFormatHoriOrient
& rHoriOri
= rFrameFormat
.GetHoriOrient();
5485 const SwFormatVertOrient
& rVertOri
= rFrameFormat
.GetVertOrient();
5486 SwFormatSurround
const& rSurround(rFrameFormat
.GetSurround());
5487 std::unique_ptr
<sax_fastparser::FastAttributeList
> pAttrList(docx::SurroundToVMLWrap(rSurround
));
5488 sShapeId
= m_rExport
.VMLExporter().AddSdrObject(*pObject
,
5489 rHoriOri
.GetHoriOrient(), rVertOri
.GetVertOrient(),
5490 rHoriOri
.GetRelationOrient(),
5491 rVertOri
.GetRelationOrient(),
5492 std::move(pAttrList
),
5495 // Restore default values
5496 m_rExport
.VMLExporter().SetSkipwzName(false);
5497 m_rExport
.VMLExporter().SetHashMarkForType(false);
5498 m_rExport
.VMLExporter().OverrideShapeIDGen(false);
5501 m_pSerializer
->singleElementNS(XML_w
, XML_control
,
5502 FSNS(XML_r
, XML_id
), sRelIdAndName
.first
,
5503 FSNS(XML_w
, XML_name
), sRelIdAndName
.second
,
5504 FSNS(XML_w
, XML_shapeid
), sShapeId
);
5507 m_pSerializer
->endElementNS(XML_w
, XML_object
);
5509 m_pSerializer
->endElementNS(XML_w
, XML_pict
);
5513 m_pSerializer
->endElementNS(XML_w
, XML_r
);
5517 bool DocxAttributeOutput::ExportAsActiveXControl(const SdrObject
* pObject
) const
5519 SdrUnoObj
*pFormObj
= const_cast<SdrUnoObj
*>(dynamic_cast< const SdrUnoObj
*>(pObject
));
5523 uno::Reference
<awt::XControlModel
> xControlModel
= pFormObj
->GetUnoControlModel();
5524 if (!xControlModel
.is())
5527 uno::Reference
< css::frame::XModel
> xModel( m_rExport
.m_rDoc
.GetDocShell() ? m_rExport
.m_rDoc
.GetDocShell()->GetModel() : nullptr );
5531 uno::Reference
<lang::XServiceInfo
> xInfo(xControlModel
, uno::UNO_QUERY
);
5535 // See WritePostponedFormControl
5536 // By now date field and combobox is handled on a different way, so let's not interfere with the other method.
5537 if(xInfo
->supportsService("com.sun.star.form.component.DateField") ||
5538 xInfo
->supportsService("com.sun.star.form.component.ComboBox"))
5541 oox::ole::OleFormCtrlExportHelper
exportHelper(comphelper::getProcessComponentContext(), xModel
, xControlModel
);
5542 return exportHelper
.isValid();
5545 void DocxAttributeOutput::PostponeOLE( SwOLENode
& rNode
, const Size
& rSize
, const SwFlyFrameFormat
* pFlyFrameFormat
)
5547 if( !m_pPostponedOLEs
)
5548 //cannot be postponed, try to write now
5549 WriteOLE( rNode
, rSize
, pFlyFrameFormat
);
5551 m_pPostponedOLEs
->push_back( PostponedOLE( &rNode
, rSize
, pFlyFrameFormat
) );
5555 * Write w:object hierarchy for embedded objects after end element of w:rPr tag.
5557 void DocxAttributeOutput::WritePostponedOLE()
5559 if( !m_pPostponedOLEs
)
5562 for( const auto & rPostponedOLE
: *m_pPostponedOLEs
)
5564 WriteOLE( *rPostponedOLE
.object
, rPostponedOLE
.size
, rPostponedOLE
.frame
);
5567 // clear list of postponed objects
5568 m_pPostponedOLEs
.reset();
5571 void DocxAttributeOutput::WriteOLE( SwOLENode
& rNode
, const Size
& rSize
, const SwFlyFrameFormat
* pFlyFrameFormat
)
5573 OSL_ASSERT(pFlyFrameFormat
);
5575 // get interoperability information about embedded objects
5576 uno::Reference
< beans::XPropertySet
> xPropSet( m_rExport
.m_rDoc
.GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW
);
5577 uno::Sequence
< beans::PropertyValue
> aGrabBag
, aObjectsInteropList
,aObjectInteropAttributes
;
5578 xPropSet
->getPropertyValue( UNO_NAME_MISC_OBJ_INTEROPGRABBAG
) >>= aGrabBag
;
5579 auto pProp
= std::find_if(aGrabBag
.begin(), aGrabBag
.end(),
5580 [](const beans::PropertyValue
& rProp
) { return rProp
.Name
== "EmbeddedObjects"; });
5581 if (pProp
!= aGrabBag
.end())
5582 pProp
->Value
>>= aObjectsInteropList
;
5584 SwOLEObj
& aObject
= rNode
.GetOLEObj();
5585 uno::Reference
< embed::XEmbeddedObject
> xObj( aObject
.GetOleRef() );
5586 comphelper::EmbeddedObjectContainer
* aContainer
= aObject
.GetObject().GetContainer();
5587 OUString sObjectName
= aContainer
->GetEmbeddedObjectName( xObj
);
5589 // set some attributes according to the type of the embedded object
5590 OUString sProgID
, sDrawAspect
;
5591 switch (rNode
.GetAspect())
5593 case embed::Aspects::MSOLE_CONTENT
: sDrawAspect
= "Content"; break;
5594 case embed::Aspects::MSOLE_DOCPRINT
: sDrawAspect
= "DocPrint"; break;
5595 case embed::Aspects::MSOLE_ICON
: sDrawAspect
= "Icon"; break;
5596 case embed::Aspects::MSOLE_THUMBNAIL
: sDrawAspect
= "Thumbnail"; break;
5598 SAL_WARN("sw.ww8", "DocxAttributeOutput::WriteOLE: invalid aspect value");
5600 auto pObjectsInterop
= std::find_if(aObjectsInteropList
.begin(), aObjectsInteropList
.end(),
5601 [&sObjectName
](const beans::PropertyValue
& rProp
) { return rProp
.Name
== sObjectName
; });
5602 if (pObjectsInterop
!= aObjectsInteropList
.end())
5603 pObjectsInterop
->Value
>>= aObjectInteropAttributes
;
5605 for( const auto& rObjectInteropAttribute
: std::as_const(aObjectInteropAttributes
) )
5607 if ( rObjectInteropAttribute
.Name
== "ProgID" )
5609 rObjectInteropAttribute
.Value
>>= sProgID
;
5613 // write embedded file
5614 OString sId
= m_rExport
.WriteOLEObject(aObject
, sProgID
);
5618 // the embedded file could not be saved
5619 // fallback: save as an image
5620 FlyFrameGraphic( nullptr, rSize
, pFlyFrameFormat
, &rNode
);
5624 // write preview image
5625 const Graphic
* pGraphic
= rNode
.GetGraphic();
5626 m_rDrawingML
.SetFS(m_pSerializer
);
5627 OUString sImageId
= m_rDrawingML
.WriteImage( *pGraphic
);
5629 if ( sDrawAspect
== "Content" )
5633 awt::Size aSize
= xObj
->getVisualAreaSize( rNode
.GetAspect() );
5635 MapUnit aUnit
= VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj
->getMapUnit( rNode
.GetAspect() ) );
5636 Size
aOriginalSize( OutputDevice::LogicToLogic(Size( aSize
.Width
, aSize
.Height
),
5637 MapMode(aUnit
), MapMode(MapUnit::MapTwip
)));
5639 m_pSerializer
->startElementNS( XML_w
, XML_object
,
5640 FSNS(XML_w
, XML_dxaOrig
), OString::number(aOriginalSize
.Width()),
5641 FSNS(XML_w
, XML_dyaOrig
), OString::number(aOriginalSize
.Height()) );
5643 catch ( uno::Exception
& )
5645 m_pSerializer
->startElementNS(XML_w
, XML_object
);
5650 m_pSerializer
->startElementNS(XML_w
, XML_object
);
5653 OString sShapeId
= "ole_" + sId
;
5655 //OLE Shape definition
5656 WriteOLEShape(*pFlyFrameFormat
, rSize
, sShapeId
, sImageId
);
5658 //OLE Object definition
5659 m_pSerializer
->singleElementNS(XML_o
, XML_OLEObject
,
5661 XML_ProgID
, sProgID
,
5662 XML_ShapeID
, sShapeId
.getStr(),
5663 XML_DrawAspect
, sDrawAspect
,
5664 XML_ObjectID
, "_" + OString::number(comphelper::rng::uniform_int_distribution(0, std::numeric_limits
<int>::max())),
5665 FSNS( XML_r
, XML_id
), sId
);
5667 m_pSerializer
->endElementNS(XML_w
, XML_object
);
5670 void DocxAttributeOutput::WriteOLEShape(const SwFlyFrameFormat
& rFrameFormat
, const Size
& rSize
,
5671 const OString
& rShapeId
, const OUString
& rImageId
)
5673 assert(m_pSerializer
);
5675 //Here is an attribute list where we collect the attributes what we want to export
5676 FastAttributeList
* pAttr
= FastSerializerHelper::createAttrList();
5677 pAttr
->add(XML_id
, rShapeId
.getStr());
5679 //export the fixed shape type for picture frame
5680 m_pSerializer
->write(vml::VMLExport::GetVMLShapeTypeDefinition(rShapeId
, true));
5681 pAttr
->add(XML_type
, "shapetype_" + rShapeId
);
5683 //Export the style attribute for position and size
5684 pAttr
->add(XML_style
, GetOLEStyle(rFrameFormat
, rSize
).getStr());
5686 const SvxBoxItem
& rBox
= rFrameFormat
.GetAttrSet().GetBox();
5689 //Word does not handle differently the four sides,
5690 //so we have to choose, and the left one is the winner:
5693 //Get the left border color and width
5694 const Color aLineColor
= rBox
.GetLeft()->GetColor();
5695 const tools::Long aLineWidth
= rBox
.GetLeft()->GetWidth();
5697 //Convert the left OLE border style to OOXML
5698 //FIXME improve if it's necessary
5699 switch (rBox
.GetLeft()->GetBorderLineStyle())
5701 case SvxBorderLineStyle::SOLID
:
5702 sLineType
= OString("Single");
5703 sDashType
= OString("Solid");
5705 case SvxBorderLineStyle::DASHED
:
5706 sLineType
= OString("Single");
5707 sDashType
= OString("Dash");
5709 case SvxBorderLineStyle::DASH_DOT
:
5710 sLineType
= OString("Single");
5711 sDashType
= OString("DashDot");
5713 case SvxBorderLineStyle::DASH_DOT_DOT
:
5714 sLineType
= OString("Single");
5715 sDashType
= OString("ShortDashDotDot");
5717 case SvxBorderLineStyle::DOTTED
:
5718 sLineType
= OString("Single");
5719 sDashType
= OString("Dot");
5721 case SvxBorderLineStyle::DOUBLE
:
5722 sLineType
= OString("ThinThin");
5723 sDashType
= OString("Solid");
5725 case SvxBorderLineStyle::DOUBLE_THIN
:
5726 sLineType
= OString("ThinThin");
5727 sDashType
= OString("Solid");
5729 case SvxBorderLineStyle::EMBOSSED
:
5730 sLineType
= OString("Single");
5731 sDashType
= OString("Solid");
5733 case SvxBorderLineStyle::ENGRAVED
:
5734 sLineType
= OString("Single");
5735 sDashType
= OString("Solid");
5737 case SvxBorderLineStyle::FINE_DASHED
:
5738 sLineType
= OString("Single");
5739 sDashType
= OString("Dot");
5741 case SvxBorderLineStyle::INSET
:
5742 sLineType
= OString("Single");
5743 sDashType
= OString("Solid");
5745 case SvxBorderLineStyle::OUTSET
:
5746 sLineType
= OString("Single");
5747 sDashType
= OString("Solid");
5749 case SvxBorderLineStyle::THICKTHIN_LARGEGAP
:
5750 case SvxBorderLineStyle::THICKTHIN_MEDIUMGAP
:
5751 case SvxBorderLineStyle::THICKTHIN_SMALLGAP
:
5752 sLineType
= OString("ThickThin");
5753 sDashType
= OString("Solid");
5755 case SvxBorderLineStyle::THINTHICK_LARGEGAP
:
5756 case SvxBorderLineStyle::THINTHICK_MEDIUMGAP
:
5757 case SvxBorderLineStyle::THINTHICK_SMALLGAP
:
5758 sLineType
= OString("ThinThick");
5759 sDashType
= OString("Solid");
5761 case SvxBorderLineStyle::NONE
:
5762 sLineType
= OString("");
5763 sDashType
= OString("");
5766 SAL_WARN("sw.ww8", "Unknown line type on OOXML ELE export!");
5770 //If there is a line add it for export
5771 if (!sLineType
.isEmpty() && !sDashType
.isEmpty())
5773 pAttr
->add(XML_stroked
, "t");
5774 pAttr
->add(XML_strokecolor
, "#" + msfilter::util::ConvertColor(aLineColor
));
5775 pAttr
->add(XML_strokeweight
, OString::number(aLineWidth
/ 20) + "pt");
5779 //Let's check the filltype of the OLE
5780 switch (rFrameFormat
.GetAttrSet().Get(XATTR_FILLSTYLE
).GetValue())
5782 case drawing::FillStyle::FillStyle_SOLID
:
5784 //If solid, we get the color and add it to the exporter
5785 const Color rShapeColor
= rFrameFormat
.GetAttrSet().Get(XATTR_FILLCOLOR
).GetColorValue();
5786 pAttr
->add(XML_filled
, "t");
5787 pAttr
->add(XML_fillcolor
, "#" + msfilter::util::ConvertColor(rShapeColor
));
5790 case drawing::FillStyle::FillStyle_GRADIENT
:
5791 case drawing::FillStyle::FillStyle_HATCH
:
5792 case drawing::FillStyle::FillStyle_BITMAP
:
5795 case drawing::FillStyle::FillStyle_NONE
:
5797 pAttr
->add(XML_filled
, "f");
5801 SAL_WARN("sw.ww8", "Unknown fill type on OOXML OLE export!");
5804 pAttr
->addNS(XML_o
, XML_ole
, ""); //compulsory, even if it's empty
5805 m_pSerializer
->startElementNS(XML_v
, XML_shape
, pAttr
);//Write the collected attrs...
5807 if (!sLineType
.isEmpty() && !sDashType
.isEmpty()) //If there is a line/dash style it is time to export it
5809 m_pSerializer
->singleElementNS(XML_v
, XML_stroke
, XML_linestyle
, sLineType
, XML_dashstyle
, sDashType
);
5812 // shape filled with the preview image
5813 m_pSerializer
->singleElementNS(XML_v
, XML_imagedata
,
5814 FSNS(XML_r
, XML_id
), rImageId
,
5815 FSNS(XML_o
, XML_title
), "");
5817 //export wrap settings
5818 if (rFrameFormat
.GetAnchor().GetAnchorId() != RndStdIds::FLY_AS_CHAR
) //As-char objs does not have surround.
5819 ExportOLESurround(rFrameFormat
.GetSurround());
5821 m_pSerializer
->endElementNS(XML_v
, XML_shape
);
5824 OString
DocxAttributeOutput::GetOLEStyle(const SwFlyFrameFormat
& rFormat
, const Size
& rSize
)
5826 //tdf#131539: Export OLE positions in docx:
5827 //This string will store the position output for the xml
5829 //This string will store the relative position for aPos
5832 if (rFormat
.GetAnchor().GetAnchorId() != RndStdIds::FLY_AS_CHAR
)
5834 //Get the horizontal alignment of the OLE via the frame format, to aHAlign
5835 OString aHAlign
= convertToOOXMLHoriOrient(rFormat
.GetHoriOrient().GetHoriOrient(),
5836 rFormat
.GetHoriOrient().IsPosToggle());
5837 //Get the vertical alignment of the OLE via the frame format to aVAlign
5838 OString aVAlign
= convertToOOXMLVertOrient(rFormat
.GetVertOrient().GetVertOrient());
5840 //Get the relative horizontal positions for the anchors
5841 OString aHAnch
= convertToOOXMLHoriOrientRel(rFormat
.GetHoriOrient().GetRelationOrient());
5842 //Get the relative vertical positions for the anchors
5843 OString aVAnch
= convertToOOXMLVertOrientRel(rFormat
.GetVertOrient().GetRelationOrient());
5845 //Choice that the horizontal position is relative or not
5846 if (!aHAlign
.isEmpty())
5847 aHAlign
= ";mso-position-horizontal:" + aHAlign
;
5848 aHAlign
= ";mso-position-horizontal-relative:" + aHAnch
;
5850 //Choice that the vertical position is relative or not
5851 if (!aVAlign
.isEmpty())
5852 aVAlign
= ";mso-position-vertical:" + aVAlign
;
5853 aVAlign
= ";mso-position-vertical-relative:" + aVAnch
;
5855 //Set the anchoring information into one string for aPos
5856 aAnch
= aHAlign
+ aVAlign
;
5858 //Query the positions to aPos from frameformat
5860 "position:absolute;margin-left:" + OString::number(double(rFormat
.GetHoriOrient().GetPos()) / 20) +
5861 "pt;margin-top:" + OString::number(double(rFormat
.GetVertOrient().GetPos()) / 20) + "pt;";
5864 OString sShapeStyle
= "width:" + OString::number( double( rSize
.Width() ) / 20 ) +
5865 "pt;height:" + OString::number( double( rSize
.Height() ) / 20 ) +
5866 "pt"; //from VMLExport::AddRectangleDimensions(), it does: value/20
5868 const SvxLRSpaceItem
& rLRSpace
= rFormat
.GetLRSpace();
5869 if (rLRSpace
.IsExplicitZeroMarginValLeft() || rLRSpace
.GetLeft())
5870 sShapeStyle
+= ";mso-wrap-distance-left:" + OString::number(double(rLRSpace
.GetLeft()) / 20) + "pt";
5871 if (rLRSpace
.IsExplicitZeroMarginValRight() || rLRSpace
.GetRight())
5872 sShapeStyle
+= ";mso-wrap-distance-right:" + OString::number(double(rLRSpace
.GetRight()) / 20) + "pt";
5873 const SvxULSpaceItem
& rULSpace
= rFormat
.GetULSpace();
5874 if (rULSpace
.GetUpper())
5875 sShapeStyle
+= ";mso-wrap-distance-top:" + OString::number(double(rULSpace
.GetUpper()) / 20) + "pt";
5876 if (rULSpace
.GetLower())
5877 sShapeStyle
+= ";mso-wrap-distance-bottom:" + OString::number(double(rULSpace
.GetLower()) / 20) + "pt";
5879 //Export anchor setting, if it exists
5880 if (!aPos
.isEmpty() && !aAnch
.isEmpty())
5881 sShapeStyle
= aPos
+ sShapeStyle
+ aAnch
;
5886 void DocxAttributeOutput::ExportOLESurround(const SwFormatSurround
& rWrap
)
5888 const bool bIsContour
= rWrap
.IsContour(); //Has the shape contour or not
5892 //Map the ODF wrap settings to OOXML one
5893 switch (rWrap
.GetSurround())
5895 case text::WrapTextMode::WrapTextMode_NONE
:
5896 sSurround
= OString("topAndBottom");
5898 case text::WrapTextMode::WrapTextMode_PARALLEL
:
5899 sSurround
= bIsContour
? OString("tight") : OString("square");
5901 case text::WrapTextMode::WrapTextMode_DYNAMIC
:
5902 sSide
= OString("largest");
5903 sSurround
= bIsContour
? OString("tight") : OString("square");
5905 case text::WrapTextMode::WrapTextMode_LEFT
:
5906 sSide
= OString("left");
5907 sSurround
= bIsContour
? OString("tight") : OString("square");
5909 case text::WrapTextMode::WrapTextMode_RIGHT
:
5910 sSide
= OString("right");
5911 sSurround
= bIsContour
? OString("tight") : OString("square");
5914 SAL_WARN("sw.ww8", "Unknown surround type on OOXML export!");
5918 //if there is a setting export it:
5919 if (!sSurround
.isEmpty())
5921 if (sSide
.isEmpty())
5922 m_pSerializer
->singleElementNS(XML_w10
, XML_wrap
, XML_type
, sSurround
);
5924 m_pSerializer
->singleElementNS(XML_w10
, XML_wrap
, XML_type
, sSurround
, XML_side
, sSide
);
5928 void DocxAttributeOutput::WritePostponedCustomShape()
5930 if (!m_pPostponedCustomShape
)
5933 for( const auto & rPostponedDrawing
: *m_pPostponedCustomShape
)
5935 if ( IsAlternateContentChoiceOpen() )
5936 m_rExport
.SdrExporter().writeDMLDrawing(rPostponedDrawing
.object
, rPostponedDrawing
.frame
, m_anchorId
++);
5938 m_rExport
.SdrExporter().writeDMLAndVMLDrawing(rPostponedDrawing
.object
, *rPostponedDrawing
.frame
, m_anchorId
++);
5940 m_pPostponedCustomShape
.reset();
5943 void DocxAttributeOutput::WritePostponedDMLDrawing()
5945 if (!m_pPostponedDMLDrawings
)
5948 // Clear the list early, this method may be called recursively.
5949 std::unique_ptr
< std::vector
<PostponedDrawing
> > pPostponedDMLDrawings(std::move(m_pPostponedDMLDrawings
));
5950 std::unique_ptr
< std::vector
<PostponedOLE
> > pPostponedOLEs(std::move(m_pPostponedOLEs
));
5952 for( const auto & rPostponedDrawing
: *pPostponedDMLDrawings
)
5954 // Avoid w:drawing within another w:drawing.
5955 if ( IsAlternateContentChoiceOpen() && !( m_rExport
.SdrExporter().IsDrawingOpen()) )
5956 m_rExport
.SdrExporter().writeDMLDrawing(rPostponedDrawing
.object
, rPostponedDrawing
.frame
, m_anchorId
++);
5958 m_rExport
.SdrExporter().writeDMLAndVMLDrawing(rPostponedDrawing
.object
, *rPostponedDrawing
.frame
, m_anchorId
++);
5961 m_pPostponedOLEs
= std::move(pPostponedOLEs
);
5964 void DocxAttributeOutput::OutputFlyFrame_Impl( const ww8::Frame
&rFrame
, const Point
& /*rNdTopLeft*/ )
5966 m_pSerializer
->mark(Tag_OutputFlyFrame
);
5968 switch ( rFrame
.GetWriterType() )
5970 case ww8::Frame::eGraphic
:
5972 const SdrObject
* pSdrObj
= rFrame
.GetFrameFormat().FindRealSdrObject();
5973 const SwNode
*pNode
= rFrame
.GetContent();
5974 const SwGrfNode
*pGrfNode
= pNode
? pNode
->GetGrfNode() : nullptr;
5977 if (!m_pPostponedGraphic
)
5979 m_bPostponedProcessingFly
= false ;
5980 FlyFrameGraphic( pGrfNode
, rFrame
.GetLayoutSize(), nullptr, nullptr, pSdrObj
);
5982 else // we are writing out attributes, but w:drawing should not be inside w:rPr,
5983 { // so write it out later
5984 m_bPostponedProcessingFly
= true ;
5985 m_pPostponedGraphic
->push_back(PostponedGraphic(pGrfNode
, rFrame
.GetLayoutSize(), pSdrObj
));
5990 case ww8::Frame::eDrawing
:
5992 const SdrObject
* pSdrObj
= rFrame
.GetFrameFormat().FindRealSdrObject();
5995 uno::Reference
<drawing::XShape
> xShape(
5996 const_cast<SdrObject
*>(pSdrObj
)->getUnoShape(), uno::UNO_QUERY
);
5998 if (xShape
.is() && oox::drawingml::DrawingML::IsDiagram(xShape
))
6000 if ( !m_pPostponedDiagrams
)
6002 m_bPostponedProcessingFly
= false ;
6003 m_rExport
.SdrExporter().writeDiagram( pSdrObj
, rFrame
.GetFrameFormat(), m_anchorId
++);
6005 else // we are writing out attributes, but w:drawing should not be inside w:rPr,
6006 { // so write it out later
6007 m_bPostponedProcessingFly
= true ;
6008 m_pPostponedDiagrams
->push_back( PostponedDiagram( pSdrObj
, &(rFrame
.GetFrameFormat()) ));
6013 if (!m_pPostponedDMLDrawings
)
6015 if ( IsAlternateContentChoiceOpen() )
6017 // Do not write w:drawing inside w:drawing. Instead Postpone the Inner Drawing.
6018 if( m_rExport
.SdrExporter().IsDrawingOpen() )
6019 m_pPostponedCustomShape
->push_back(PostponedDrawing(pSdrObj
, &(rFrame
.GetFrameFormat())));
6021 m_rExport
.SdrExporter().writeDMLDrawing( pSdrObj
, &rFrame
.GetFrameFormat(), m_anchorId
++);
6024 m_rExport
.SdrExporter().writeDMLAndVMLDrawing( pSdrObj
, rFrame
.GetFrameFormat(), m_anchorId
++);
6026 m_bPostponedProcessingFly
= false ;
6028 // IsAlternateContentChoiceOpen(): check is to ensure that only one object is getting added. Without this check, plus one object gets added
6029 // m_bParagraphFrameOpen: check if the frame is open.
6030 else if (IsAlternateContentChoiceOpen() && m_bParagraphFrameOpen
)
6031 m_pPostponedCustomShape
->push_back(PostponedDrawing(pSdrObj
, &(rFrame
.GetFrameFormat())));
6034 // we are writing out attributes, but w:drawing should not be inside w:rPr, so write it out later
6035 m_bPostponedProcessingFly
= true ;
6036 m_pPostponedDMLDrawings
->push_back(PostponedDrawing(pSdrObj
, &(rFrame
.GetFrameFormat())));
6042 case ww8::Frame::eTextBox
:
6044 // If this is a TextBox of a shape, then ignore: it's handled in WriteTextBox().
6045 if (DocxSdrExport::isTextBox(rFrame
.GetFrameFormat()))
6048 // If this is a TextBox containing a table which we already exported directly, ignore it
6049 if (m_aFloatingTablesOfParagraph
.find(&rFrame
.GetFrameFormat()) != m_aFloatingTablesOfParagraph
.end())
6052 // The frame output is postponed to the end of the anchor paragraph
6053 bool bDuplicate
= false;
6054 const OUString
& rName
= rFrame
.GetFrameFormat().GetName();
6055 unsigned nSize
= m_aFramesOfParagraph
.size();
6056 for( unsigned nIndex
= 0; nIndex
< nSize
; ++nIndex
)
6058 const OUString
& rNameExisting
= m_aFramesOfParagraph
[nIndex
].GetFrameFormat().GetName();
6060 if (!rName
.isEmpty() && !rNameExisting
.isEmpty())
6062 if (rName
== rNameExisting
)
6069 m_bPostponedProcessingFly
= true ;
6070 m_aFramesOfParagraph
.emplace_back(rFrame
);
6074 case ww8::Frame::eOle
:
6076 const SwFrameFormat
&rFrameFormat
= rFrame
.GetFrameFormat();
6077 const SdrObject
*pSdrObj
= rFrameFormat
.FindRealSdrObject();
6080 SwNodeIndex
aIdx(*rFrameFormat
.GetContent().GetContentIdx(), 1);
6081 SwOLENode
& rOLENd
= *aIdx
.GetNode().GetOLENode();
6083 //output variable for the formula alignment (default inline)
6084 sal_Int8
nAlign(FormulaExportBase::eFormulaAlign::INLINE
);
6085 auto xObj(rOLENd
.GetOLEObj().GetOleRef()); //get the xObject of the formula
6087 //tdf133030: Export formula position
6088 //If we have a formula with inline anchor...
6089 if(SotExchange::IsMath(xObj
->getClassID()) && rFrame
.IsInline())
6091 SwPosition
const* const aAPos
= rFrameFormat
.GetAnchor().GetContentAnchor();
6094 //Get the text node what the formula anchored to
6095 const SwTextNode
* pTextNode
= aAPos
->nNode
.GetNode().GetTextNode();
6096 if(pTextNode
&& pTextNode
->Len() == 1)
6098 //Get the paragraph alignment
6099 auto aParaAdjust
= pTextNode
->GetSwAttrSet().GetAdjust().GetAdjust();
6100 //And set the formula according to the paragraph alignment
6101 if (aParaAdjust
== SvxAdjust::Center
)
6102 nAlign
= FormulaExportBase::eFormulaAlign::CENTER
;
6103 else if (aParaAdjust
== SvxAdjust::Right
)
6104 nAlign
= FormulaExportBase::eFormulaAlign::RIGHT
;
6105 else // left in the case of left and justified paragraph alignments
6106 nAlign
= FormulaExportBase::eFormulaAlign::LEFT
;
6110 WriteOLE2Obj( pSdrObj
, rOLENd
, rFrame
.GetLayoutSize(), dynamic_cast<const SwFlyFrameFormat
*>( &rFrameFormat
), nAlign
);
6111 m_bPostponedProcessingFly
= false ;
6115 case ww8::Frame::eFormControl
:
6117 const SdrObject
* pObject
= rFrame
.GetFrameFormat().FindRealSdrObject();
6118 if(ExportAsActiveXControl(pObject
))
6119 m_aPostponedActiveXControls
.emplace_back(pObject
, &(rFrame
.GetFrameFormat()));
6121 m_aPostponedFormControls
.push_back(pObject
);
6122 m_bPostponedProcessingFly
= true ;
6126 SAL_INFO("sw.ww8", "TODO DocxAttributeOutput::OutputFlyFrame_Impl( const ww8::Frame& rFrame ) - frame type " <<
6127 ( rFrame
.GetWriterType() == ww8::Frame::eTextBox
? "eTextBox":
6128 ( rFrame
.GetWriterType() == ww8::Frame::eOle
? "eOle": "???" ) ) );
6132 m_pSerializer
->mergeTopMarks(Tag_OutputFlyFrame
);
6135 void DocxAttributeOutput::WriteOutliner(const OutlinerParaObject
& rParaObj
)
6137 const EditTextObject
& rEditObj
= rParaObj
.GetTextObject();
6138 MSWord_SdrAttrIter
aAttrIter( m_rExport
, rEditObj
, TXT_HFTXTBOX
);
6140 sal_Int32 nPara
= rEditObj
.GetParagraphCount();
6142 m_pSerializer
->startElementNS(XML_w
, XML_txbxContent
);
6143 for (sal_Int32 n
= 0; n
< nPara
; ++n
)
6146 aAttrIter
.NextPara( n
);
6148 OUString
aStr( rEditObj
.GetText( n
));
6149 sal_Int32 nCurrentPos
= 0;
6150 sal_Int32 nEnd
= aStr
.getLength();
6152 StartParagraph(ww8::WW8TableNodeInfo::Pointer_t());
6154 // Write paragraph properties.
6155 StartParagraphProperties();
6156 aAttrIter
.OutParaAttr(false);
6157 SfxItemSet
aParagraphMarkerProperties(m_rExport
.m_rDoc
.GetAttrPool());
6158 EndParagraphProperties(aParagraphMarkerProperties
, nullptr, nullptr, nullptr);
6161 const sal_Int32 nNextAttr
= std::min(aAttrIter
.WhereNext(), nEnd
);
6163 m_pSerializer
->startElementNS(XML_w
, XML_r
);
6165 // Write run properties.
6166 m_pSerializer
->startElementNS(XML_w
, XML_rPr
);
6167 aAttrIter
.OutAttr(nCurrentPos
);
6168 WriteCollectedRunProperties();
6169 m_pSerializer
->endElementNS(XML_w
, XML_rPr
);
6171 bool bTextAtr
= aAttrIter
.IsTextAttr( nCurrentPos
);
6174 OUString
aOut( aStr
.copy( nCurrentPos
, nNextAttr
- nCurrentPos
) );
6178 if ( !m_sRawText
.isEmpty() )
6180 RunText( m_sRawText
);
6184 m_pSerializer
->endElementNS( XML_w
, XML_r
);
6186 nCurrentPos
= nNextAttr
;
6187 aAttrIter
.NextPos();
6189 while( nCurrentPos
< nEnd
);
6190 // Word can't handle nested text boxes, so write them on the same level.
6191 ++m_nTextFrameLevel
;
6192 EndParagraph(ww8::WW8TableNodeInfoInner::Pointer_t());
6193 --m_nTextFrameLevel
;
6195 m_pSerializer
->endElementNS( XML_w
, XML_txbxContent
);
6198 void DocxAttributeOutput::pushToTableExportContext(DocxTableExportContext
& rContext
)
6200 rContext
.m_pTableInfo
= m_rExport
.m_pTableInfo
;
6201 m_rExport
.m_pTableInfo
= std::make_shared
<ww8::WW8TableInfo
>();
6203 rContext
.m_bTableCellOpen
= m_tableReference
->m_bTableCellOpen
;
6204 m_tableReference
->m_bTableCellOpen
= false;
6206 rContext
.m_nTableDepth
= m_tableReference
->m_nTableDepth
;
6207 m_tableReference
->m_nTableDepth
= 0;
6209 rContext
.m_bStartedParaSdt
= m_bStartedParaSdt
;
6210 m_bStartedParaSdt
= false;
6213 void DocxAttributeOutput::popFromTableExportContext(DocxTableExportContext
const & rContext
)
6215 m_rExport
.m_pTableInfo
= rContext
.m_pTableInfo
;
6216 m_tableReference
->m_bTableCellOpen
= rContext
.m_bTableCellOpen
;
6217 m_tableReference
->m_nTableDepth
= rContext
.m_nTableDepth
;
6218 m_bStartedParaSdt
= rContext
.m_bStartedParaSdt
;
6221 void DocxAttributeOutput::WriteTextBox(uno::Reference
<drawing::XShape
> xShape
)
6223 DocxTableExportContext
aTableExportContext(*this);
6225 SwFrameFormat
* pTextBox
= SwTextBoxHelper::getOtherTextBoxFormat(xShape
);
6227 const SwPosition
* pAnchor
= nullptr;
6228 if (pTextBox
->GetAnchor().GetAnchorId() == RndStdIds::FLY_AT_PAGE
) //tdf135711
6230 auto pNdIdx
= pTextBox
->GetContent().GetContentIdx();
6231 if (pNdIdx
) //Is that possible it is null?
6232 pAnchor
= new SwPosition(*pNdIdx
);
6236 pAnchor
= pTextBox
->GetAnchor().GetContentAnchor();//This might be null
6239 if (pAnchor
) //pAnchor can be null, so that's why not assert here.
6241 ww8::Frame
aFrame(*pTextBox
, *pAnchor
);
6242 m_rExport
.SdrExporter().writeDMLTextFrame(&aFrame
, m_anchorId
++, /*bTextBoxOnly=*/true);
6243 if (pTextBox
->GetAnchor().GetAnchorId() == RndStdIds::FLY_AT_PAGE
)
6250 void DocxAttributeOutput::WriteVMLTextBox(uno::Reference
<drawing::XShape
> xShape
)
6252 DocxTableExportContext
aTableExportContext(*this);
6254 SwFrameFormat
* pTextBox
= SwTextBoxHelper::getOtherTextBoxFormat(xShape
);
6256 const SwPosition
* pAnchor
= nullptr;
6257 if (pTextBox
->GetAnchor().GetAnchorId() == RndStdIds::FLY_AT_PAGE
) //tdf135711
6259 auto pNdIdx
= pTextBox
->GetContent().GetContentIdx();
6260 if (pNdIdx
) //Is that possible it is null?
6261 pAnchor
= new SwPosition(*pNdIdx
);
6265 pAnchor
= pTextBox
->GetAnchor().GetContentAnchor();//This might be null
6268 if (pAnchor
) //pAnchor can be null, so that's why not assert here.
6270 ww8::Frame
aFrame(*pTextBox
, *pAnchor
);
6271 m_rExport
.SdrExporter().writeVMLTextFrame(&aFrame
, /*bTextBoxOnly=*/true);
6272 if (pTextBox
->GetAnchor().GetAnchorId() == RndStdIds::FLY_AT_PAGE
)
6279 oox::drawingml::DrawingML
& DocxAttributeOutput::GetDrawingML()
6281 return m_rDrawingML
;
6284 void DocxAttributeOutput::MaybeOutputBrushItem(SfxItemSet
const& rSet
)
6286 const XFillStyleItem
* pXFillStyleItem(rSet
.GetItem
<XFillStyleItem
>(XATTR_FILLSTYLE
));
6288 if ((pXFillStyleItem
&& pXFillStyleItem
->GetValue() != drawing::FillStyle_NONE
)
6289 || !m_rExport
.SdrExporter().getDMLTextFrameSyntax())
6294 // sw text frames are opaque by default, even with fill none!
6295 std::unique_ptr
<SfxItemSet
> const pClone(rSet
.Clone());
6296 XFillColorItem
const aColor(OUString(), COL_WHITE
);
6297 pClone
->Put(aColor
);
6298 // call getSvxBrushItemForSolid - this also takes XFillTransparenceItem into account
6299 XFillStyleItem
const aSolid(drawing::FillStyle_SOLID
);
6300 pClone
->Put(aSolid
);
6301 std::unique_ptr
<SvxBrushItem
> const pBrush(getSvxBrushItemFromSourceSet(*pClone
, RES_BACKGROUND
));
6302 FormatBackground(*pBrush
);
6307 /// Functor to do case-insensitive ordering of OUString instances.
6308 struct OUStringIgnoreCase
6310 bool operator() (const OUString
& lhs
, std::u16string_view rhs
) const
6312 return lhs
.compareToIgnoreAsciiCase(rhs
) < 0;
6318 /// Guesses if a style created in Writer (no grab-bag) should be qFormat or not.
6319 static bool lcl_guessQFormat(const OUString
& rName
, sal_uInt16 nWwId
)
6321 // If the style has no dedicated STI number, then it's probably a custom style -> qFormat.
6322 if (nWwId
== ww::stiUser
)
6325 // Allow exported built-in styles UI language neutral
6326 if ( nWwId
== ww::stiNormal
||
6327 ( nWwId
>= ww::stiLev1
&& nWwId
<= ww::stiLev9
) ||
6328 nWwId
== ww::stiCaption
|| nWwId
== ww::stiTitle
||
6329 nWwId
== ww::stiSubtitle
|| nWwId
== ww::stiStrong
||
6330 nWwId
== ww::stiEmphasis
)
6333 static o3tl::sorted_vector
<OUString
, OUStringIgnoreCase
> const aAllowlist
6342 "Intense Reference",
6346 // Not custom style? Then we have a list of standard styles which should be qFormat.
6347 return aAllowlist
.find(rName
) != aAllowlist
.end();
6350 void DocxAttributeOutput::StartStyle( const OUString
& rName
, StyleType eType
,
6351 sal_uInt16 nBase
, sal_uInt16 nNext
, sal_uInt16 nWwId
, sal_uInt16 nId
, bool bAutoUpdate
)
6353 bool bQFormat
= false, bUnhideWhenUsed
= false, bSemiHidden
= false, bLocked
= false, bDefault
= false, bCustomStyle
= false;
6354 OUString aLink
, aRsid
, aUiPriority
;
6355 FastAttributeList
* pStyleAttributeList
= FastSerializerHelper::createAttrList();
6357 if (eType
== STYLE_TYPE_PARA
|| eType
== STYLE_TYPE_CHAR
)
6359 const SwFormat
* pFormat
= m_rExport
.m_pStyles
->GetSwFormat(nId
);
6360 pFormat
->GetGrabBagItem(aAny
);
6364 const SwNumRule
* pRule
= m_rExport
.m_pStyles
->GetSwNumRule(nId
);
6365 pRule
->GetGrabBagItem(aAny
);
6367 const uno::Sequence
<beans::PropertyValue
>& rGrabBag
= aAny
.get
< uno::Sequence
<beans::PropertyValue
> >();
6369 for (const auto& rProp
: rGrabBag
)
6371 if (rProp
.Name
== "uiPriority")
6372 aUiPriority
= rProp
.Value
.get
<OUString
>();
6373 else if (rProp
.Name
== "qFormat")
6375 else if (rProp
.Name
== "link")
6376 aLink
= rProp
.Value
.get
<OUString
>();
6377 else if (rProp
.Name
== "rsid")
6378 aRsid
= rProp
.Value
.get
<OUString
>();
6379 else if (rProp
.Name
== "unhideWhenUsed")
6380 bUnhideWhenUsed
= true;
6381 else if (rProp
.Name
== "semiHidden")
6383 else if (rProp
.Name
== "locked")
6385 else if (rProp
.Name
== "default")
6386 bDefault
= rProp
.Value
.get
<bool>();
6387 else if (rProp
.Name
== "customStyle")
6388 bCustomStyle
= rProp
.Value
.get
<bool>();
6390 SAL_WARN("sw.ww8", "Unhandled style property: " << rProp
.Name
);
6393 // MSO exports English names and writerfilter only recognize them.
6394 const char *pEnglishName
= nullptr;
6395 const char* pType
= nullptr;
6398 case STYLE_TYPE_PARA
:
6399 pType
= "paragraph";
6400 if ( nWwId
< ww::stiMax
)
6401 pEnglishName
= ww::GetEnglishNameFromSti( static_cast<ww::sti
>(nWwId
) );
6403 case STYLE_TYPE_CHAR
: pType
= "character"; break;
6404 case STYLE_TYPE_LIST
: pType
= "numbering"; break;
6406 pStyleAttributeList
->add(FSNS( XML_w
, XML_type
), pType
);
6407 pStyleAttributeList
->add(FSNS( XML_w
, XML_styleId
), m_rExport
.m_pStyles
->GetStyleId(nId
).getStr());
6409 pStyleAttributeList
->add(FSNS(XML_w
, XML_default
), "1");
6411 pStyleAttributeList
->add(FSNS(XML_w
, XML_customStyle
), "1");
6412 XFastAttributeListRef
xStyleAttributeList(pStyleAttributeList
);
6413 m_pSerializer
->startElementNS( XML_w
, XML_style
, xStyleAttributeList
);
6414 m_pSerializer
->singleElementNS( XML_w
, XML_name
,
6415 FSNS( XML_w
, XML_val
), pEnglishName
? pEnglishName
: rName
.toUtf8() );
6417 if ( nBase
!= 0x0FFF && eType
!= STYLE_TYPE_LIST
)
6419 m_pSerializer
->singleElementNS( XML_w
, XML_basedOn
,
6420 FSNS( XML_w
, XML_val
), m_rExport
.m_pStyles
->GetStyleId(nBase
) );
6423 if ( nNext
!= nId
&& eType
!= STYLE_TYPE_LIST
)
6425 m_pSerializer
->singleElementNS( XML_w
, XML_next
,
6426 FSNS( XML_w
, XML_val
), m_rExport
.m_pStyles
->GetStyleId(nNext
) );
6429 if (!aLink
.isEmpty())
6430 m_pSerializer
->singleElementNS(XML_w
, XML_link
, FSNS(XML_w
, XML_val
), aLink
);
6433 m_pSerializer
->singleElementNS(XML_w
, XML_autoRedefine
);
6435 if (!aUiPriority
.isEmpty())
6436 m_pSerializer
->singleElementNS(XML_w
, XML_uiPriority
, FSNS(XML_w
, XML_val
), aUiPriority
);
6438 m_pSerializer
->singleElementNS(XML_w
, XML_semiHidden
);
6439 if (bUnhideWhenUsed
)
6440 m_pSerializer
->singleElementNS(XML_w
, XML_unhideWhenUsed
);
6442 if (bQFormat
|| lcl_guessQFormat(rName
, nWwId
))
6443 m_pSerializer
->singleElementNS(XML_w
, XML_qFormat
);
6445 m_pSerializer
->singleElementNS(XML_w
, XML_locked
);
6446 if (!aRsid
.isEmpty())
6447 m_pSerializer
->singleElementNS(XML_w
, XML_rsid
, FSNS(XML_w
, XML_val
), aRsid
);
6450 void DocxAttributeOutput::EndStyle()
6452 m_pSerializer
->endElementNS( XML_w
, XML_style
);
6455 void DocxAttributeOutput::StartStyleProperties( bool bParProp
, sal_uInt16
/*nStyle*/ )
6459 m_pSerializer
->startElementNS(XML_w
, XML_pPr
);
6460 InitCollectedParagraphProperties();
6464 m_pSerializer
->startElementNS(XML_w
, XML_rPr
);
6465 InitCollectedRunProperties();
6469 void DocxAttributeOutput::EndStyleProperties( bool bParProp
)
6473 WriteCollectedParagraphProperties();
6475 // Merge the marks for the ordered elements
6476 m_pSerializer
->mergeTopMarks(Tag_InitCollectedParagraphProperties
);
6478 m_pSerializer
->endElementNS( XML_w
, XML_pPr
);
6482 WriteCollectedRunProperties();
6484 // Merge the marks for the ordered elements
6485 m_pSerializer
->mergeTopMarks(Tag_InitCollectedRunProperties
);
6487 m_pSerializer
->endElementNS( XML_w
, XML_rPr
);
6494 void lcl_OutlineLevel(sax_fastparser::FSHelperPtr
const & pSerializer
, sal_uInt16 nLevel
)
6496 if (nLevel
>= WW8ListManager::nMaxLevel
)
6497 nLevel
= WW8ListManager::nMaxLevel
- 1;
6499 pSerializer
->singleElementNS(XML_w
, XML_outlineLvl
,
6500 FSNS(XML_w
, XML_val
), OString::number(nLevel
));
6505 void DocxAttributeOutput::OutlineNumbering(sal_uInt8
const /*nLvl*/)
6507 // Handled by ParaOutlineLevel() instead.
6510 void DocxAttributeOutput::ParaOutlineLevel(const SfxUInt16Item
& rItem
)
6512 if (rItem
.GetValue() > 0)
6513 lcl_OutlineLevel(m_pSerializer
, rItem
.GetValue() - 1);
6516 void DocxAttributeOutput::PageBreakBefore( bool bBreak
)
6519 m_pSerializer
->singleElementNS(XML_w
, XML_pageBreakBefore
);
6521 m_pSerializer
->singleElementNS( XML_w
, XML_pageBreakBefore
,
6522 FSNS( XML_w
, XML_val
), "false" );
6525 void DocxAttributeOutput::SectionBreak( sal_uInt8 nC
, bool bBreakAfter
, const WW8_SepInfo
* pSectionInfo
)
6529 case msword::ColumnBreak
:
6530 // The column break should be output in the next paragraph...
6531 if ( m_nColBreakStatus
== COLBRK_WRITE
)
6532 m_nColBreakStatus
= COLBRK_WRITEANDPOSTPONE
;
6534 m_nColBreakStatus
= COLBRK_POSTPONE
;
6536 case msword::PageBreak
:
6539 // Detect when the current node is the last node in the
6540 // document: the last section is written explicitly in
6541 // DocxExport::WriteMainText(), don't duplicate that here.
6542 SwNodeIndex
aCurrentNode(m_rExport
.m_pCurPam
->GetNode());
6543 SwNodeIndex
aLastNode(m_rExport
.m_rDoc
.GetNodes().GetEndOfContent(), -1);
6544 bool bEmit
= aCurrentNode
!= aLastNode
;
6548 // Need to still emit an empty section at the end of the
6549 // document in case balanced columns are wanted, since the last
6550 // section in Word is always balanced.
6551 sal_uInt16 nColumns
= 1;
6552 bool bBalance
= false;
6553 if (const SwSectionFormat
* pFormat
= pSectionInfo
->pSectionFormat
)
6555 if (pFormat
!= reinterpret_cast<SwSectionFormat
*>(sal_IntPtr(-1)))
6557 nColumns
= pFormat
->GetCol().GetNumCols();
6558 const SwFormatNoBalancedColumns
& rNoBalanced
= pFormat
->GetBalancedColumns();
6559 bBalance
= !rNoBalanced
.GetValue();
6562 bEmit
= (nColumns
> 1 && bBalance
);
6565 // don't add section properties if this will be the first
6566 // paragraph in the document
6567 if ( !m_bParagraphOpened
&& !m_bIsFirstParagraph
&& bEmit
)
6569 // Create a dummy paragraph if needed
6570 m_pSerializer
->startElementNS(XML_w
, XML_p
);
6571 m_pSerializer
->startElementNS(XML_w
, XML_pPr
);
6573 m_rExport
.SectionProperties( *pSectionInfo
);
6575 m_pSerializer
->endElementNS( XML_w
, XML_pPr
);
6576 m_pSerializer
->endElementNS( XML_w
, XML_p
);
6580 // postpone the output of this; it has to be done inside the
6581 // paragraph properties, so remember it until then
6582 m_pSectionInfo
.reset( new WW8_SepInfo( *pSectionInfo
));
6585 else if ( m_bParagraphOpened
)
6589 m_bPageBreakAfter
= true;
6592 m_pSerializer
->startElementNS(XML_w
, XML_r
);
6593 m_pSerializer
->singleElementNS(XML_w
, XML_br
, FSNS(XML_w
, XML_type
), "page");
6594 m_pSerializer
->endElementNS(XML_w
, XML_r
);
6598 m_bPostponedPageBreak
= true;
6602 SAL_INFO("sw.ww8", "Unknown section break to write: " << nC
);
6607 void DocxAttributeOutput::EndParaSdtBlock()
6609 if (m_bStartedParaSdt
)
6611 // Paragraph-level SDT still open? Close it now.
6613 m_bStartedParaSdt
= false;
6617 void DocxAttributeOutput::StartSection()
6619 m_pSerializer
->startElementNS(XML_w
, XML_sectPr
);
6620 m_bOpenedSectPr
= true;
6622 // Write the elements in the spec order
6623 static const sal_Int32 aOrder
[] =
6625 FSNS( XML_w
, XML_headerReference
),
6626 FSNS( XML_w
, XML_footerReference
),
6627 FSNS( XML_w
, XML_footnotePr
),
6628 FSNS( XML_w
, XML_endnotePr
),
6629 FSNS( XML_w
, XML_type
),
6630 FSNS( XML_w
, XML_pgSz
),
6631 FSNS( XML_w
, XML_pgMar
),
6632 FSNS( XML_w
, XML_paperSrc
),
6633 FSNS( XML_w
, XML_pgBorders
),
6634 FSNS( XML_w
, XML_lnNumType
),
6635 FSNS( XML_w
, XML_pgNumType
),
6636 FSNS( XML_w
, XML_cols
),
6637 FSNS( XML_w
, XML_formProt
),
6638 FSNS( XML_w
, XML_vAlign
),
6639 FSNS( XML_w
, XML_noEndnote
),
6640 FSNS( XML_w
, XML_titlePg
),
6641 FSNS( XML_w
, XML_textDirection
),
6642 FSNS( XML_w
, XML_bidi
),
6643 FSNS( XML_w
, XML_rtlGutter
),
6644 FSNS( XML_w
, XML_docGrid
),
6645 FSNS( XML_w
, XML_printerSettings
),
6646 FSNS( XML_w
, XML_sectPrChange
)
6649 // postpone the output so that we can later [in EndParagraphProperties()]
6650 // prepend the properties before the run
6651 m_pSerializer
->mark(Tag_StartSection
, comphelper::containerToSequence(aOrder
));
6652 m_bHadSectPr
= true;
6655 void DocxAttributeOutput::EndSection()
6657 // Write the section properties
6658 if ( m_pSectionSpacingAttrList
.is() )
6660 XFastAttributeListRef
xAttrList( m_pSectionSpacingAttrList
.get() );
6661 m_pSectionSpacingAttrList
.clear();
6663 m_pSerializer
->singleElementNS( XML_w
, XML_pgMar
, xAttrList
);
6666 // Order the elements
6667 m_pSerializer
->mergeTopMarks(Tag_StartSection
);
6669 m_pSerializer
->endElementNS( XML_w
, XML_sectPr
);
6670 m_bOpenedSectPr
= false;
6673 void DocxAttributeOutput::SectionFormProtection( bool bProtected
)
6676 m_pSerializer
->singleElementNS(XML_w
, XML_formProt
, FSNS(XML_w
, XML_val
), "true");
6678 m_pSerializer
->singleElementNS(XML_w
, XML_formProt
, FSNS(XML_w
, XML_val
), "false");
6681 void DocxAttributeOutput::SectionLineNumbering( sal_uLong nRestartNo
, const SwLineNumberInfo
& rLnNumInfo
)
6683 FastAttributeList
* pAttr
= FastSerializerHelper::createAttrList();
6684 pAttr
->add( FSNS( XML_w
, XML_countBy
), OString::number(rLnNumInfo
.GetCountBy()).getStr());
6685 pAttr
->add( FSNS( XML_w
, XML_restart
), rLnNumInfo
.IsRestartEachPage() ? "newPage" : "continuous" );
6686 if( rLnNumInfo
.GetPosFromLeft())
6687 pAttr
->add( FSNS( XML_w
, XML_distance
), OString::number(rLnNumInfo
.GetPosFromLeft()).getStr());
6689 // Writer is 1-based, Word is 0-based.
6690 pAttr
->add(FSNS(XML_w
, XML_start
), OString::number(nRestartNo
- 1).getStr());
6691 XFastAttributeListRef
xAttrs( pAttr
);
6692 m_pSerializer
->singleElementNS( XML_w
, XML_lnNumType
, xAttrs
);
6695 void DocxAttributeOutput::SectionTitlePage()
6697 m_pSerializer
->singleElementNS(XML_w
, XML_titlePg
);
6700 void DocxAttributeOutput::SectionPageBorders( const SwFrameFormat
* pFormat
, const SwFrameFormat
* /*pFirstPageFormat*/ )
6702 // Output the margins
6704 const SvxBoxItem
& rBox
= pFormat
->GetBox( );
6706 const SvxBorderLine
* pLeft
= rBox
.GetLeft( );
6707 const SvxBorderLine
* pTop
= rBox
.GetTop( );
6708 const SvxBorderLine
* pRight
= rBox
.GetRight( );
6709 const SvxBorderLine
* pBottom
= rBox
.GetBottom( );
6711 if ( !(pBottom
|| pTop
|| pLeft
|| pRight
) )
6714 OutputBorderOptions aOutputBorderOptions
= lcl_getBoxBorderOptions();
6716 // Check if there is a shadow item
6717 const SfxPoolItem
* pItem
= GetExport().HasItem( RES_SHADOW
);
6720 const SvxShadowItem
* pShadowItem
= static_cast<const SvxShadowItem
*>(pItem
);
6721 aOutputBorderOptions
.aShadowLocation
= pShadowItem
->GetLocation();
6724 // By top margin, impl_borders() means the distance between the top of the page and the header frame.
6725 editeng::WordPageMargins aMargins
= m_pageMargins
;
6726 HdFtDistanceGlue
aGlue(pFormat
->GetAttrSet());
6727 if (aGlue
.HasHeader())
6728 aMargins
.nTop
= aGlue
.dyaHdrTop
;
6729 // Ditto for bottom margin.
6730 if (aGlue
.HasFooter())
6731 aMargins
.nBottom
= aGlue
.dyaHdrBottom
;
6733 aOutputBorderOptions
.pDistances
= std::make_shared
<editeng::WordBorderDistances
>();
6734 editeng::BorderDistancesToWord(rBox
, aMargins
, *aOutputBorderOptions
.pDistances
);
6736 // All distances are relative to the text margins
6737 m_pSerializer
->startElementNS(XML_w
, XML_pgBorders
,
6738 FSNS(XML_w
, XML_display
), "allPages",
6739 FSNS(XML_w
, XML_offsetFrom
), aOutputBorderOptions
.pDistances
->bFromEdge
? "page" : "text");
6741 std::map
<SvxBoxItemLine
, css::table::BorderLine2
> aEmptyMap
; // empty styles map
6742 impl_borders( m_pSerializer
, rBox
, aOutputBorderOptions
, aEmptyMap
);
6744 m_pSerializer
->endElementNS( XML_w
, XML_pgBorders
);
6748 void DocxAttributeOutput::SectionBiDi( bool bBiDi
)
6751 m_pSerializer
->singleElementNS(XML_w
, XML_bidi
);
6754 static OString
impl_NumberingType( sal_uInt16 nNumberingType
)
6758 switch ( nNumberingType
)
6760 case SVX_NUM_CHARS_UPPER_LETTER
:
6761 case SVX_NUM_CHARS_UPPER_LETTER_N
: aType
= "upperLetter"; break;
6762 case SVX_NUM_CHARS_LOWER_LETTER
:
6763 case SVX_NUM_CHARS_LOWER_LETTER_N
: aType
= "lowerLetter"; break;
6764 case SVX_NUM_ROMAN_UPPER
: aType
= "upperRoman"; break;
6765 case SVX_NUM_ROMAN_LOWER
: aType
= "lowerRoman"; break;
6767 case SVX_NUM_ARABIC
: aType
= "decimal"; break;
6769 case SVX_NUM_BITMAP
:
6770 case SVX_NUM_CHAR_SPECIAL
: aType
= "bullet"; break;
6772 case style::NumberingType::CHARS_HEBREW
: aType
= "hebrew2"; break;
6773 case style::NumberingType::NUMBER_HEBREW
: aType
= "hebrew1"; break;
6775 default: aType
= "none"; break;
6781 // Converting Level Numbering Format Code to string
6782 static OString
impl_LevelNFC(sal_uInt16 nNumberingType
, const SfxItemSet
* pOutSet
, OString
& rFormat
)
6786 switch ( nNumberingType
)
6788 case style::NumberingType::CHARS_UPPER_LETTER
:
6789 case style::NumberingType::CHARS_UPPER_LETTER_N
:
6790 case style::NumberingType::CHARS_LOWER_LETTER
:
6791 case style::NumberingType::CHARS_LOWER_LETTER_N
:
6792 case style::NumberingType::ROMAN_UPPER
:
6793 case style::NumberingType::ROMAN_LOWER
:
6794 case style::NumberingType::ARABIC
:
6795 case style::NumberingType::BITMAP
:
6796 case style::NumberingType::CHAR_SPECIAL
:
6797 case style::NumberingType::CHARS_HEBREW
:
6798 case style::NumberingType::NUMBER_HEBREW
:
6799 case style::NumberingType::NUMBER_NONE
:
6800 return impl_NumberingType( nNumberingType
);
6801 case style::NumberingType::FULLWIDTH_ARABIC
: aType
="decimalFullWidth"; break;
6802 case style::NumberingType::TIAN_GAN_ZH
: aType
="ideographTraditional"; break;
6803 case style::NumberingType::DI_ZI_ZH
: aType
="ideographZodiac"; break;
6804 case style::NumberingType::NUMBER_LOWER_ZH
:
6805 aType
="taiwaneseCountingThousand";
6807 const SvxLanguageItem
& rLang
= pOutSet
->Get( RES_CHRATR_CJK_LANGUAGE
);
6808 const LanguageType eLang
= rLang
.GetLanguage();
6810 if (LANGUAGE_CHINESE_SIMPLIFIED
== eLang
) {
6811 aType
="chineseCountingThousand";
6815 case style::NumberingType::NUMBER_UPPER_ZH_TW
: aType
="ideographLegalTraditional";break;
6816 case style::NumberingType::NUMBER_UPPER_ZH
: aType
="chineseLegalSimplified"; break;
6817 case style::NumberingType::NUMBER_TRADITIONAL_JA
: aType
="japaneseLegal";break;
6818 case style::NumberingType::AIU_FULLWIDTH_JA
: aType
="aiueoFullWidth";break;
6819 case style::NumberingType::AIU_HALFWIDTH_JA
: aType
="aiueo";break;
6820 case style::NumberingType::IROHA_FULLWIDTH_JA
: aType
="iroha";break;
6821 case style::NumberingType::IROHA_HALFWIDTH_JA
: aType
="irohaFullWidth";break;
6822 case style::NumberingType::HANGUL_SYLLABLE_KO
: aType
="ganada";break;
6823 case style::NumberingType::HANGUL_JAMO_KO
: aType
="chosung";break;
6824 case style::NumberingType::NUMBER_HANGUL_KO
: aType
="koreanDigital";break;
6825 case style::NumberingType::NUMBER_UPPER_KO
: aType
="koreanLegal"; break;
6826 case style::NumberingType::CIRCLE_NUMBER
: aType
="decimalEnclosedCircle"; break;
6827 case style::NumberingType::CHARS_ARABIC
: aType
="arabicAlpha"; break;
6828 case style::NumberingType::CHARS_THAI
: aType
="thaiLetters"; break;
6829 case style::NumberingType::CHARS_PERSIAN
: aType
="hindiVowels"; break;
6830 case style::NumberingType::CHARS_CYRILLIC_UPPER_LETTER_RU
:
6831 case style::NumberingType::CHARS_CYRILLIC_UPPER_LETTER_N_RU
: aType
= "russianUpper"; break;
6832 case style::NumberingType::CHARS_CYRILLIC_LOWER_LETTER_RU
:
6833 case style::NumberingType::CHARS_CYRILLIC_LOWER_LETTER_N_RU
: aType
= "russianLower"; break;
6834 case style::NumberingType::TEXT_NUMBER
: aType
="ordinal"; break;
6835 case style::NumberingType::TEXT_CARDINAL
: aType
="cardinalText"; break;
6836 case style::NumberingType::TEXT_ORDINAL
: aType
="ordinalText"; break;
6837 case style::NumberingType::SYMBOL_CHICAGO
: aType
="chicago"; break;
6838 case style::NumberingType::ARABIC_ZERO
: aType
= "decimalZero"; break;
6839 case style::NumberingType::ARABIC_ZERO3
:
6841 rFormat
= "001, 002, 003, ...";
6843 case style::NumberingType::ARABIC_ZERO4
:
6845 rFormat
= "0001, 0002, 0003, ...";
6847 case style::NumberingType::ARABIC_ZERO5
:
6849 rFormat
= "00001, 00002, 00003, ...";
6852 Fallback the rest to decimal.
6853 case style::NumberingType::NATIVE_NUMBERING:
6854 case style::NumberingType::HANGUL_CIRCLED_JAMO_KO:
6855 case style::NumberingType::HANGUL_CIRCLED_SYLLABLE_KO:
6856 case style::NumberingType::CHARS_GREEK_UPPER_LETTER:
6857 case style::NumberingType::CHARS_GREEK_LOWER_LETTER:
6858 case style::NumberingType::PAGE_DESCRIPTOR:
6859 case style::NumberingType::TRANSLITERATION:
6860 case style::NumberingType::CHARS_NEPALI:
6861 case style::NumberingType::CHARS_KHMER:
6862 case style::NumberingType::CHARS_LAO:
6863 case style::NumberingType::CHARS_TIBETAN:
6864 case style::NumberingType::CHARS_CYRILLIC_UPPER_LETTER_BG:
6865 case style::NumberingType::CHARS_CYRILLIC_LOWER_LETTER_BG:
6866 case style::NumberingType::CHARS_CYRILLIC_UPPER_LETTER_N_BG:
6867 case style::NumberingType::CHARS_CYRILLIC_LOWER_LETTER_N_BG:
6868 case style::NumberingType::CHARS_MYANMAR:
6869 case style::NumberingType::CHARS_CYRILLIC_UPPER_LETTER_SR:
6870 case style::NumberingType::CHARS_CYRILLIC_LOWER_LETTER_SR:
6871 case style::NumberingType::CHARS_CYRILLIC_UPPER_LETTER_N_SR:
6872 case style::NumberingType::CHARS_CYRILLIC_LOWER_LETTER_N_SR:
6875 aType
= "decimal"; break;
6881 void DocxAttributeOutput::SectionPageNumbering( sal_uInt16 nNumType
, const ::std::optional
<sal_uInt16
>& oPageRestartNumber
)
6883 // FIXME Not called properly with page styles like "First Page"
6885 FastAttributeList
* pAttr
= FastSerializerHelper::createAttrList();
6887 // std::nullopt means no restart: then don't output that attribute if it is negative
6888 if ( oPageRestartNumber
)
6889 pAttr
->add( FSNS( XML_w
, XML_start
), OString::number( *oPageRestartNumber
) );
6891 // nNumType corresponds to w:fmt. See WW8Export::GetNumId() for more precisions
6892 OString
aFormat( impl_NumberingType( nNumType
) );
6893 if ( !aFormat
.isEmpty() )
6894 pAttr
->add( FSNS( XML_w
, XML_fmt
), aFormat
.getStr() );
6896 XFastAttributeListRef
xAttrs( pAttr
);
6897 m_pSerializer
->singleElementNS( XML_w
, XML_pgNumType
, xAttrs
);
6899 // see 2.6.12 pgNumType (Page Numbering Settings)
6900 SAL_INFO("sw.ww8", "TODO DocxAttributeOutput::SectionPageNumbering()" );
6903 void DocxAttributeOutput::SectionType( sal_uInt8 nBreakCode
)
6905 /* break code: 0 No break, 1 New column
6906 2 New page, 3 Even page, 4 Odd page
6909 switch ( nBreakCode
)
6911 case 1: pType
= "nextColumn"; break;
6912 case 2: pType
= "nextPage"; break;
6913 case 3: pType
= "evenPage"; break;
6914 case 4: pType
= "oddPage"; break;
6915 default: pType
= "continuous"; break;
6918 m_pSerializer
->singleElementNS(XML_w
, XML_type
, FSNS(XML_w
, XML_val
), pType
);
6921 void DocxAttributeOutput::TextVerticalAdjustment( const drawing::TextVerticalAdjust nVA
)
6925 case drawing::TextVerticalAdjust_CENTER
:
6926 m_pSerializer
->singleElementNS(XML_w
, XML_vAlign
, FSNS(XML_w
, XML_val
), "center");
6928 case drawing::TextVerticalAdjust_BOTTOM
:
6929 m_pSerializer
->singleElementNS(XML_w
, XML_vAlign
, FSNS(XML_w
, XML_val
), "bottom");
6931 case drawing::TextVerticalAdjust_BLOCK
: //justify
6932 m_pSerializer
->singleElementNS(XML_w
, XML_vAlign
, FSNS(XML_w
, XML_val
), "both");
6939 void DocxAttributeOutput::StartFont( const OUString
& rFamilyName
) const
6941 m_pSerializer
->startElementNS(XML_w
, XML_font
, FSNS(XML_w
, XML_name
), rFamilyName
);
6944 void DocxAttributeOutput::EndFont() const
6946 m_pSerializer
->endElementNS( XML_w
, XML_font
);
6949 void DocxAttributeOutput::FontAlternateName( const OUString
& rName
) const
6951 m_pSerializer
->singleElementNS(XML_w
, XML_altName
, FSNS(XML_w
, XML_val
), rName
);
6954 void DocxAttributeOutput::FontCharset( sal_uInt8 nCharSet
, rtl_TextEncoding nEncoding
) const
6956 FastAttributeList
* pAttr
= FastSerializerHelper::createAttrList();
6958 OString
aCharSet( OString::number( nCharSet
, 16 ) );
6959 if ( aCharSet
.getLength() == 1 )
6960 aCharSet
= "0" + aCharSet
;
6961 pAttr
->add( FSNS( XML_w
, XML_val
), aCharSet
.getStr());
6963 if( GetExport().GetFilter().getVersion( ) != oox::core::ECMA_DIALECT
)
6965 if( const char* charset
= rtl_getMimeCharsetFromTextEncoding( nEncoding
))
6966 pAttr
->add( FSNS( XML_w
, XML_characterSet
), charset
);
6969 m_pSerializer
->singleElementNS( XML_w
, XML_charset
, XFastAttributeListRef( pAttr
));
6972 void DocxAttributeOutput::FontFamilyType( FontFamily eFamily
) const
6974 const char* pFamily
;
6977 case FAMILY_ROMAN
: pFamily
= "roman"; break;
6978 case FAMILY_SWISS
: pFamily
= "swiss"; break;
6979 case FAMILY_MODERN
: pFamily
= "modern"; break;
6980 case FAMILY_SCRIPT
: pFamily
= "script"; break;
6981 case FAMILY_DECORATIVE
: pFamily
= "decorative"; break;
6982 default: pFamily
= "auto"; break; // no font family
6985 m_pSerializer
->singleElementNS(XML_w
, XML_family
, FSNS(XML_w
, XML_val
), pFamily
);
6988 void DocxAttributeOutput::FontPitchType( FontPitch ePitch
) const
6993 case PITCH_VARIABLE
: pPitch
= "variable"; break;
6994 case PITCH_FIXED
: pPitch
= "fixed"; break;
6995 default: pPitch
= "default"; break; // no info about the pitch
6998 m_pSerializer
->singleElementNS(XML_w
, XML_pitch
, FSNS(XML_w
, XML_val
), pPitch
);
7001 void DocxAttributeOutput::EmbedFont( const OUString
& name
, FontFamily family
, FontPitch pitch
)
7003 if( !m_rExport
.m_rDoc
.getIDocumentSettingAccess().get( DocumentSettingId::EMBED_FONTS
))
7004 return; // no font embedding with this document
7005 EmbedFontStyle( name
, XML_embedRegular
, family
, ITALIC_NONE
, WEIGHT_NORMAL
, pitch
);
7006 EmbedFontStyle( name
, XML_embedBold
, family
, ITALIC_NONE
, WEIGHT_BOLD
, pitch
);
7007 EmbedFontStyle( name
, XML_embedItalic
, family
, ITALIC_NORMAL
, WEIGHT_NORMAL
, pitch
);
7008 EmbedFontStyle( name
, XML_embedBoldItalic
, family
, ITALIC_NORMAL
, WEIGHT_BOLD
, pitch
);
7011 static char toHexChar( int value
)
7013 return value
>= 10 ? value
+ 'A' - 10 : value
+ '0';
7016 void DocxAttributeOutput::EmbedFontStyle( const OUString
& name
, int tag
, FontFamily family
, FontItalic italic
,
7017 FontWeight weight
, FontPitch pitch
)
7019 // Embed font if at least viewing is allowed (in which case the opening app must check
7020 // the font license rights too and open either read-only or not use the font for editing).
7021 OUString fontUrl
= EmbeddedFontsHelper::fontFileUrl( name
, family
, italic
, weight
, pitch
,
7022 EmbeddedFontsHelper::FontRights::ViewingAllowed
);
7023 if( fontUrl
.isEmpty())
7025 // TODO IDocumentSettingAccess::EMBED_SYSTEM_FONTS
7026 if( !fontFilesMap
.count( fontUrl
))
7028 osl::File
file( fontUrl
);
7029 if( file
.open( osl_File_OpenFlag_Read
) != osl::File::E_None
)
7031 uno::Reference
< css::io::XOutputStream
> xOutStream
= m_rExport
.GetFilter().openFragmentStream(
7032 "word/fonts/font" + OUString::number(m_nextFontId
) + ".odttf",
7033 "application/vnd.openxmlformats-officedocument.obfuscatedFont" );
7034 // Not much point in trying hard with the obfuscation key, whoever reads the spec can read the font anyway,
7035 // so just alter the first and last part of the key.
7036 char fontKeyStr
[] = "{00014A78-CABC-4EF0-12AC-5CD89AEFDE00}";
7037 sal_uInt8 fontKey
[ 16 ] = { 0, 0xDE, 0xEF, 0x9A, 0xD8, 0x5C, 0xAC, 0x12, 0xF0, 0x4E,
7038 0xBC, 0xCA, 0x78, 0x4A, 0x01, 0 };
7039 fontKey
[ 0 ] = fontKey
[ 15 ] = m_nextFontId
% 256;
7040 fontKeyStr
[ 1 ] = fontKeyStr
[ 35 ] = toHexChar(( m_nextFontId
% 256 ) / 16 );
7041 fontKeyStr
[ 2 ] = fontKeyStr
[ 36 ] = toHexChar(( m_nextFontId
% 256 ) % 16 );
7042 unsigned char buffer
[ 4096 ];
7043 sal_uInt64 readSize
;
7044 file
.read( buffer
, 32, readSize
);
7047 SAL_WARN( "sw.ww8", "Font file size too small (" << fontUrl
<< ")" );
7048 xOutStream
->closeOutput();
7055 buffer
[ i
] ^= fontKey
[ i
];
7056 buffer
[ i
+ 16 ] ^= fontKey
[ i
];
7058 xOutStream
->writeBytes( uno::Sequence
< sal_Int8
>( reinterpret_cast< const sal_Int8
* >( buffer
), 32 ));
7062 if( file
.isEndOfFile( &eof
) != osl::File::E_None
)
7064 SAL_WARN( "sw.ww8", "Error reading font file " << fontUrl
);
7065 xOutStream
->closeOutput();
7070 if( file
.read( buffer
, 4096, readSize
) != osl::File::E_None
)
7072 SAL_WARN( "sw.ww8", "Error reading font file " << fontUrl
);
7073 xOutStream
->closeOutput();
7078 // coverity[overrun-buffer-arg : FALSE] - coverity has difficulty with css::uno::Sequence
7079 xOutStream
->writeBytes( uno::Sequence
< sal_Int8
>( reinterpret_cast< const sal_Int8
* >( buffer
), readSize
));
7081 xOutStream
->closeOutput();
7082 OString relId
= OUStringToOString( GetExport().GetFilter().addRelation( m_pSerializer
->getOutputStream(),
7083 oox::getRelationship(Relationship::FONT
),
7084 "fonts/font" + OUString::number( m_nextFontId
) + ".odttf" ), RTL_TEXTENCODING_UTF8
);
7085 EmbeddedFontRef ref
;
7087 ref
.fontKey
= fontKeyStr
;
7088 fontFilesMap
[ fontUrl
] = ref
;
7091 m_pSerializer
->singleElementNS( XML_w
, tag
,
7092 FSNS( XML_r
, XML_id
), fontFilesMap
[ fontUrl
].relId
,
7093 FSNS( XML_w
, XML_fontKey
), fontFilesMap
[ fontUrl
].fontKey
);
7096 OString
DocxAttributeOutput::TransHighlightColor( sal_uInt8 nIco
)
7100 case 1: return "black"; break;
7101 case 2: return "blue"; break;
7102 case 3: return "cyan"; break;
7103 case 4: return "green"; break;
7104 case 5: return "magenta"; break;
7105 case 6: return "red"; break;
7106 case 7: return "yellow"; break;
7107 case 8: return "white"; break;
7108 case 9: return "darkBlue"; break;
7109 case 10: return "darkCyan"; break;
7110 case 11: return "darkGreen"; break;
7111 case 12: return "darkMagenta"; break;
7112 case 13: return "darkRed"; break;
7113 case 14: return "darkYellow"; break;
7114 case 15: return "darkGray"; break;
7115 case 16: return "lightGray"; break;
7116 default: return OString(); break;
7120 void DocxAttributeOutput::NumberingDefinition( sal_uInt16 nId
, const SwNumRule
&rRule
)
7122 // nId is the same both for abstract numbering definition as well as the
7123 // numbering definition itself
7124 // TODO check that this is actually true & fix if not ;-)
7125 OString
aId( OString::number( nId
) );
7127 m_pSerializer
->startElementNS(XML_w
, XML_num
, FSNS(XML_w
, XML_numId
), aId
);
7129 m_pSerializer
->singleElementNS(XML_w
, XML_abstractNumId
, FSNS(XML_w
, XML_val
), aId
);
7131 #if OSL_DEBUG_LEVEL > 1
7132 // TODO ww8 version writes this, anything to do about it here?
7133 if ( rRule
.IsContinusNum() )
7134 SAL_INFO("sw", "TODO DocxAttributeOutput::NumberingDefinition()" );
7136 (void) rRule
; // to quiet the warning...
7139 m_pSerializer
->endElementNS( XML_w
, XML_num
);
7142 // Not all attributes of SwNumFormat are important for export, so can't just use embedded in
7143 // that classes comparison.
7144 static bool lcl_ListLevelsAreDifferentForExport(const SwNumFormat
& rFormat1
, const SwNumFormat
& rFormat2
)
7146 if (rFormat1
== rFormat2
)
7147 // They are equal, nothing to do
7150 if (!rFormat1
.GetCharFormat() != !rFormat2
.GetCharFormat())
7151 // One has charformat, other not. they are different
7154 if (rFormat1
.GetCharFormat() && rFormat2
.GetCharFormat())
7156 const SwAttrSet
& a1
= rFormat1
.GetCharFormat()->GetAttrSet();
7157 const SwAttrSet
& a2
= rFormat2
.GetCharFormat()->GetAttrSet();
7160 // Difference in charformat: they are different
7164 // Compare numformats with empty charformats
7165 SwNumFormat modified1
= rFormat1
;
7166 SwNumFormat modified2
= rFormat2
;
7167 modified1
.SetCharFormatName(OUString());
7168 modified2
.SetCharFormatName(OUString());
7169 modified1
.SetCharFormat(nullptr);
7170 modified2
.SetCharFormat(nullptr);
7171 return modified1
!= modified2
;
7174 void DocxAttributeOutput::OverrideNumberingDefinition(
7175 SwNumRule
const& rRule
,
7176 sal_uInt16
const nNum
, sal_uInt16
const nAbstractNum
, const std::map
< size_t, size_t > & rLevelOverrides
)
7178 m_pSerializer
->startElementNS(XML_w
, XML_num
, FSNS(XML_w
, XML_numId
), OString::number(nNum
));
7180 m_pSerializer
->singleElementNS(XML_w
, XML_abstractNumId
, FSNS(XML_w
, XML_val
), OString::number(nAbstractNum
));
7182 SwNumRule
const& rAbstractRule
= *(*m_rExport
.m_pUsedNumTable
)[nAbstractNum
- 1];
7183 sal_uInt8
const nLevels
= static_cast<sal_uInt8
>(rRule
.IsContinusNum()
7184 ? WW8ListManager::nMinLevel
: WW8ListManager::nMaxLevel
);
7185 for (sal_uInt8 nLevel
= 0; nLevel
< nLevels
; ++nLevel
)
7187 const auto levelOverride
= rLevelOverrides
.find(nLevel
);
7188 bool bListsAreDifferent
= lcl_ListLevelsAreDifferentForExport(rRule
.Get(nLevel
), rAbstractRule
.Get(nLevel
));
7190 // Export list override only if it is different to abstract one
7191 // or we have a level numbering override
7192 if (bListsAreDifferent
|| levelOverride
!= rLevelOverrides
.end())
7194 m_pSerializer
->startElementNS(XML_w
, XML_lvlOverride
, FSNS(XML_w
, XML_ilvl
), OString::number(nLevel
));
7196 if (bListsAreDifferent
)
7198 GetExport().NumberingLevel(rRule
, nLevel
);
7200 if (levelOverride
!= rLevelOverrides
.end())
7202 // list numbering restart override
7203 m_pSerializer
->singleElementNS(XML_w
, XML_startOverride
,
7204 FSNS(XML_w
, XML_val
), OString::number(levelOverride
->second
));
7207 m_pSerializer
->endElementNS(XML_w
, XML_lvlOverride
);
7211 m_pSerializer
->endElementNS( XML_w
, XML_num
);
7214 void DocxAttributeOutput::StartAbstractNumbering( sal_uInt16 nId
)
7216 const SwNumRule
* pRule
= (*m_rExport
.m_pUsedNumTable
)[nId
- 1];
7217 m_bExportingOutline
= pRule
&& pRule
->IsOutlineRule();
7218 m_pSerializer
->startElementNS( XML_w
, XML_abstractNum
,
7219 FSNS( XML_w
, XML_abstractNumId
), OString::number(nId
) );
7222 void DocxAttributeOutput::EndAbstractNumbering()
7224 m_pSerializer
->endElementNS( XML_w
, XML_abstractNum
);
7227 void DocxAttributeOutput::NumberingLevel( sal_uInt8 nLevel
,
7229 sal_uInt16 nNumberingType
,
7231 const sal_uInt8
* /*pNumLvlPos*/,
7233 const wwFont
*pFont
,
7234 const SfxItemSet
*pOutSet
,
7235 sal_Int16 nIndentAt
,
7236 sal_Int16 nFirstLineIndex
,
7237 sal_Int16 nListTabPos
,
7238 const OUString
&rNumberingString
,
7239 const SvxBrushItem
* pBrush
)
7241 m_pSerializer
->startElementNS(XML_w
, XML_lvl
, FSNS(XML_w
, XML_ilvl
), OString::number(nLevel
));
7243 // start with the nStart value. Do not write w:start if Numbered Lists
7244 // starts from zero.As it's an optional parameter.
7245 // refer ECMA 376 Second edition Part-1
7246 if(0 != nLevel
|| 0 != nStart
)
7248 m_pSerializer
->singleElementNS( XML_w
, XML_start
,
7249 FSNS( XML_w
, XML_val
), OString::number(nStart
) );
7252 if (m_bExportingOutline
)
7254 sal_uInt16 nId
= m_rExport
.m_pStyles
->GetHeadingParagraphStyleId( nLevel
);
7255 if ( nId
!= SAL_MAX_UINT16
)
7256 m_pSerializer
->singleElementNS( XML_w
, XML_pStyle
,
7257 FSNS( XML_w
, XML_val
), m_rExport
.m_pStyles
->GetStyleId(nId
) );
7260 OString aCustomFormat
;
7261 OString
aFormat(impl_LevelNFC(nNumberingType
, pOutSet
, aCustomFormat
));
7263 if ( !aFormat
.isEmpty() )
7265 if (aCustomFormat
.isEmpty())
7267 m_pSerializer
->singleElementNS(XML_w
, XML_numFmt
, FSNS(XML_w
, XML_val
), aFormat
);
7271 m_pSerializer
->startElementNS(XML_mc
, XML_AlternateContent
);
7272 m_pSerializer
->startElementNS(XML_mc
, XML_Choice
, XML_Requires
, "w14");
7274 m_pSerializer
->singleElementNS(XML_w
, XML_numFmt
, FSNS(XML_w
, XML_val
), aFormat
,
7275 FSNS(XML_w
, XML_format
), aCustomFormat
);
7277 m_pSerializer
->endElementNS(XML_mc
, XML_Choice
);
7278 m_pSerializer
->startElementNS(XML_mc
, XML_Fallback
);
7279 m_pSerializer
->singleElementNS(XML_w
, XML_numFmt
, FSNS(XML_w
, XML_val
), "decimal");
7280 m_pSerializer
->endElementNS(XML_mc
, XML_Fallback
);
7281 m_pSerializer
->endElementNS(XML_mc
, XML_AlternateContent
);
7286 const char *pSuffix
= nullptr;
7289 case 1: pSuffix
= "space"; break;
7290 case 2: pSuffix
= "nothing"; break;
7291 default: /*pSuffix = "tab";*/ break;
7294 m_pSerializer
->singleElementNS(XML_w
, XML_suff
, FSNS(XML_w
, XML_val
), pSuffix
);
7297 OUStringBuffer
aBuffer( rNumberingString
.getLength() + WW8ListManager::nMaxLevel
);
7299 const sal_Unicode
*pPrev
= rNumberingString
.getStr();
7300 const sal_Unicode
*pIt
= rNumberingString
.getStr();
7301 while ( pIt
< rNumberingString
.getStr() + rNumberingString
.getLength() )
7303 // convert the level values to %NUMBER form
7304 // (we don't use pNumLvlPos at all)
7305 // FIXME so far we support the ww8 limit of levels only
7306 if ( *pIt
< sal_Unicode( WW8ListManager::nMaxLevel
) )
7308 aBuffer
.append( pPrev
, pIt
- pPrev
);
7309 aBuffer
.append( '%' );
7310 aBuffer
.append( OUString::number( sal_Int32( *pIt
) + 1 ) );
7317 aBuffer
.append( pPrev
, pIt
- pPrev
);
7319 // If bullet char is empty, set lvlText as empty
7320 if ( rNumberingString
== OUStringChar('\0') && nNumberingType
== SVX_NUM_CHAR_SPECIAL
)
7322 m_pSerializer
->singleElementNS(XML_w
, XML_lvlText
, FSNS(XML_w
, XML_val
), "");
7326 // Writer's "zero width space" suffix is necessary, so that LabelFollowedBy shows up, but Word doesn't require that.
7327 OUString aLevelText
= aBuffer
.makeStringAndClear();
7328 static OUString
aZeroWidthSpace(u
'\x200B');
7329 if (aLevelText
== aZeroWidthSpace
)
7331 m_pSerializer
->singleElementNS(XML_w
, XML_lvlText
, FSNS(XML_w
, XML_val
), aLevelText
);
7335 if (nNumberingType
== SVX_NUM_BITMAP
&& pBrush
)
7337 int nIndex
= m_rExport
.GetGrfIndex(*pBrush
);
7340 m_pSerializer
->singleElementNS(XML_w
, XML_lvlPicBulletId
,
7341 FSNS(XML_w
, XML_val
), OString::number(nIndex
));
7347 bool ecmaDialect
= ( m_rExport
.GetFilter().getVersion() == oox::core::ECMA_DIALECT
);
7350 case SvxAdjust::Center
: pJc
= "center"; break;
7351 case SvxAdjust::Right
: pJc
= !ecmaDialect
? "end" : "right"; break;
7352 default: pJc
= !ecmaDialect
? "start" : "left"; break;
7354 m_pSerializer
->singleElementNS(XML_w
, XML_lvlJc
, FSNS(XML_w
, XML_val
), pJc
);
7357 m_pSerializer
->startElementNS(XML_w
, XML_pPr
);
7358 if( nListTabPos
>= 0 )
7360 m_pSerializer
->startElementNS(XML_w
, XML_tabs
);
7361 m_pSerializer
->singleElementNS( XML_w
, XML_tab
,
7362 FSNS( XML_w
, XML_val
), "num",
7363 FSNS( XML_w
, XML_pos
), OString::number(nListTabPos
) );
7364 m_pSerializer
->endElementNS( XML_w
, XML_tabs
);
7367 sal_Int32 nToken
= ecmaDialect
? XML_left
: XML_start
;
7368 sal_Int32 nIndentToken
= nFirstLineIndex
> 0 ? XML_firstLine
: XML_hanging
;
7369 m_pSerializer
->singleElementNS( XML_w
, XML_ind
,
7370 FSNS( XML_w
, nToken
), OString::number(nIndentAt
),
7371 FSNS( XML_w
, nIndentToken
), OString::number(abs(nFirstLineIndex
)) );
7372 m_pSerializer
->endElementNS( XML_w
, XML_pPr
);
7377 m_pSerializer
->startElementNS(XML_w
, XML_rPr
);
7379 SfxItemSet
aTempSet(*pOutSet
);
7382 GetExport().GetId( *pFont
); // ensure font info is written to fontTable.xml
7383 OString
aFamilyName( OUStringToOString( pFont
->GetFamilyName(), RTL_TEXTENCODING_UTF8
) );
7384 m_pSerializer
->singleElementNS( XML_w
, XML_rFonts
,
7385 FSNS( XML_w
, XML_ascii
), aFamilyName
,
7386 FSNS( XML_w
, XML_hAnsi
), aFamilyName
,
7387 FSNS( XML_w
, XML_cs
), aFamilyName
,
7388 FSNS( XML_w
, XML_hint
), "default" );
7389 aTempSet
.ClearItem(RES_CHRATR_FONT
);
7390 aTempSet
.ClearItem(RES_CHRATR_CTL_FONT
);
7392 m_rExport
.OutputItemSet(aTempSet
, false, true, i18n::ScriptType::LATIN
, m_rExport
.m_bExportModeRTF
);
7394 WriteCollectedRunProperties();
7396 m_pSerializer
->endElementNS( XML_w
, XML_rPr
);
7399 // TODO anything to do about nListTabPos?
7401 m_pSerializer
->endElementNS( XML_w
, XML_lvl
);
7404 void DocxAttributeOutput::CharCaseMap( const SvxCaseMapItem
& rCaseMap
)
7406 switch ( rCaseMap
.GetValue() )
7408 case SvxCaseMap::SmallCaps
:
7409 m_pSerializer
->singleElementNS(XML_w
, XML_smallCaps
);
7411 case SvxCaseMap::Uppercase
:
7412 m_pSerializer
->singleElementNS(XML_w
, XML_caps
);
7414 default: // Something that ooxml does not support
7415 m_pSerializer
->singleElementNS(XML_w
, XML_smallCaps
, FSNS(XML_w
, XML_val
), "false");
7416 m_pSerializer
->singleElementNS(XML_w
, XML_caps
, FSNS(XML_w
, XML_val
), "false");
7421 void DocxAttributeOutput::CharColor( const SvxColorItem
& rColor
)
7423 const Color
aColor( rColor
.GetValue() );
7424 OString aColorString
= msfilter::util::ConvertColor( aColor
);
7426 const char* pExistingValue(nullptr);
7427 if (m_pColorAttrList
.is() && m_pColorAttrList
->getAsChar(FSNS(XML_w
, XML_val
), pExistingValue
))
7429 assert(aColorString
.equalsL(pExistingValue
, rtl_str_getLength(pExistingValue
)));
7433 AddToAttrList( m_pColorAttrList
, FSNS( XML_w
, XML_val
), aColorString
.getStr() );
7434 m_nCharTransparence
= aColor
.GetTransparency();
7437 void DocxAttributeOutput::CharContour( const SvxContourItem
& rContour
)
7439 if ( rContour
.GetValue() )
7440 m_pSerializer
->singleElementNS(XML_w
, XML_outline
);
7442 m_pSerializer
->singleElementNS(XML_w
, XML_outline
, FSNS(XML_w
, XML_val
), "false");
7445 void DocxAttributeOutput::CharCrossedOut( const SvxCrossedOutItem
& rCrossedOut
)
7447 switch ( rCrossedOut
.GetStrikeout() )
7449 case STRIKEOUT_DOUBLE
:
7450 m_pSerializer
->singleElementNS(XML_w
, XML_dstrike
);
7452 case STRIKEOUT_NONE
:
7453 m_pSerializer
->singleElementNS(XML_w
, XML_dstrike
, FSNS(XML_w
, XML_val
), "false");
7454 m_pSerializer
->singleElementNS(XML_w
, XML_strike
, FSNS(XML_w
, XML_val
), "false");
7457 m_pSerializer
->singleElementNS(XML_w
, XML_strike
);
7462 void DocxAttributeOutput::CharEscapement( const SvxEscapementItem
& rEscapement
)
7465 short nEsc
= rEscapement
.GetEsc(), nProp
= rEscapement
.GetProportionalHeight();
7467 // Simplify styles to avoid impossible complexity. Import and export as defaults only
7468 if ( m_rExport
.m_bStyDef
&& nEsc
)
7470 nProp
= DFLT_ESC_PROP
;
7471 nEsc
= (nEsc
> 0) ? DFLT_ESC_AUTO_SUPER
: DFLT_ESC_AUTO_SUB
;
7476 sIss
= OString( "baseline" );
7480 else if ( DFLT_ESC_PROP
== nProp
|| nProp
< 1 || nProp
> 100 )
7482 if ( DFLT_ESC_SUB
== nEsc
|| DFLT_ESC_AUTO_SUB
== nEsc
)
7483 sIss
= OString( "subscript" );
7484 else if ( DFLT_ESC_SUPER
== nEsc
|| DFLT_ESC_AUTO_SUPER
== nEsc
)
7485 sIss
= OString( "superscript" );
7487 else if ( DFLT_ESC_AUTO_SUPER
== nEsc
)
7489 // Raised by the differences between the ascenders (ascent = baseline to top of highest letter).
7490 // The ascent is generally about 80% of the total font height.
7491 // That is why DFLT_ESC_PROP (58) leads to 33% (DFLT_ESC_SUPER)
7492 nEsc
= .8 * (100 - nProp
);
7494 else if ( DFLT_ESC_AUTO_SUB
== nEsc
)
7496 // Lowered by the differences between the descenders (descent = baseline to bottom of lowest letter).
7497 // The descent is generally about 20% of the total font height.
7498 // That is why DFLT_ESC_PROP (58) leads to 8% (DFLT_ESC_SUB)
7499 nEsc
= .2 * -(100 - nProp
);
7502 if ( !sIss
.isEmpty() )
7503 m_pSerializer
->singleElementNS(XML_w
, XML_vertAlign
, FSNS(XML_w
, XML_val
), sIss
);
7505 if (sIss
.isEmpty() || sIss
.match("baseline"))
7507 const SvxFontHeightItem
& rItem
= m_rExport
.GetItem(RES_CHRATR_FONTSIZE
);
7508 float fHeight
= rItem
.GetHeight();
7509 OString sPos
= OString::number( round(( fHeight
* nEsc
) / 1000) );
7510 m_pSerializer
->singleElementNS(XML_w
, XML_position
, FSNS(XML_w
, XML_val
), sPos
);
7512 if( ( 100 != nProp
|| sIss
.match( "baseline" ) ) && !m_rExport
.m_bFontSizeWritten
)
7514 OString sSize
= OString::number( round(( fHeight
* nProp
) / 1000) );
7515 m_pSerializer
->singleElementNS(XML_w
, XML_sz
, FSNS(XML_w
, XML_val
), sSize
);
7520 void DocxAttributeOutput::CharFont( const SvxFontItem
& rFont
)
7522 GetExport().GetId( rFont
); // ensure font info is written to fontTable.xml
7523 const OUString
& sFontName(rFont
.GetFamilyName());
7524 const OString sFontNameUtf8
= OUStringToOString(sFontName
, RTL_TEXTENCODING_UTF8
);
7525 if (sFontNameUtf8
.isEmpty())
7528 if (m_pFontsAttrList
&&
7529 ( m_pFontsAttrList
->hasAttribute(FSNS( XML_w
, XML_ascii
)) ||
7530 m_pFontsAttrList
->hasAttribute(FSNS( XML_w
, XML_hAnsi
)) )
7533 // tdf#38778: do to fields output into DOC the font could be added before and after field declaration
7534 // that all sub runs of the field will have correct font inside.
7535 // For DOCX we should do not add the same font information twice in the same node
7539 AddToAttrList( m_pFontsAttrList
, 2,
7540 FSNS( XML_w
, XML_ascii
), sFontNameUtf8
.getStr(),
7541 FSNS( XML_w
, XML_hAnsi
), sFontNameUtf8
.getStr() );
7544 void DocxAttributeOutput::CharFontSize( const SvxFontHeightItem
& rFontSize
)
7546 OString fontSize
= OString::number( ( rFontSize
.GetHeight() + 5 ) / 10 );
7548 switch ( rFontSize
.Which() )
7550 case RES_CHRATR_FONTSIZE
:
7551 case RES_CHRATR_CJK_FONTSIZE
:
7552 m_pSerializer
->singleElementNS(XML_w
, XML_sz
, FSNS(XML_w
, XML_val
), fontSize
);
7554 case RES_CHRATR_CTL_FONTSIZE
:
7555 m_pSerializer
->singleElementNS(XML_w
, XML_szCs
, FSNS(XML_w
, XML_val
), fontSize
);
7560 void DocxAttributeOutput::CharKerning( const SvxKerningItem
& rKerning
)
7562 OString aKerning
= OString::number( rKerning
.GetValue() );
7563 m_pSerializer
->singleElementNS(XML_w
, XML_spacing
, FSNS(XML_w
, XML_val
), aKerning
);
7566 void DocxAttributeOutput::CharLanguage( const SvxLanguageItem
& rLanguage
)
7568 OString
aLanguageCode( OUStringToOString(
7569 LanguageTag( rLanguage
.GetLanguage()).getBcp47MS(),
7570 RTL_TEXTENCODING_UTF8
));
7572 switch ( rLanguage
.Which() )
7574 case RES_CHRATR_LANGUAGE
:
7575 AddToAttrList( m_pCharLangAttrList
, FSNS( XML_w
, XML_val
), aLanguageCode
.getStr() );
7577 case RES_CHRATR_CJK_LANGUAGE
:
7578 AddToAttrList( m_pCharLangAttrList
, FSNS( XML_w
, XML_eastAsia
), aLanguageCode
.getStr() );
7580 case RES_CHRATR_CTL_LANGUAGE
:
7581 AddToAttrList( m_pCharLangAttrList
, FSNS( XML_w
, XML_bidi
), aLanguageCode
.getStr() );
7586 void DocxAttributeOutput::CharPosture( const SvxPostureItem
& rPosture
)
7588 if ( rPosture
.GetPosture() != ITALIC_NONE
)
7589 m_pSerializer
->singleElementNS(XML_w
, XML_i
);
7591 m_pSerializer
->singleElementNS(XML_w
, XML_i
, FSNS(XML_w
, XML_val
), "false");
7594 void DocxAttributeOutput::CharShadow( const SvxShadowedItem
& rShadow
)
7596 if ( rShadow
.GetValue() )
7597 m_pSerializer
->singleElementNS(XML_w
, XML_shadow
);
7599 m_pSerializer
->singleElementNS(XML_w
, XML_shadow
, FSNS(XML_w
, XML_val
), "false");
7602 void DocxAttributeOutput::CharUnderline( const SvxUnderlineItem
& rUnderline
)
7604 const char *pUnderlineValue
;
7606 switch ( rUnderline
.GetLineStyle() )
7608 case LINESTYLE_SINGLE
: pUnderlineValue
= "single"; break;
7609 case LINESTYLE_BOLD
: pUnderlineValue
= "thick"; break;
7610 case LINESTYLE_DOUBLE
: pUnderlineValue
= "double"; break;
7611 case LINESTYLE_DOTTED
: pUnderlineValue
= "dotted"; break;
7612 case LINESTYLE_DASH
: pUnderlineValue
= "dash"; break;
7613 case LINESTYLE_DASHDOT
: pUnderlineValue
= "dotDash"; break;
7614 case LINESTYLE_DASHDOTDOT
: pUnderlineValue
= "dotDotDash"; break;
7615 case LINESTYLE_WAVE
: pUnderlineValue
= "wave"; break;
7616 case LINESTYLE_BOLDDOTTED
: pUnderlineValue
= "dottedHeavy"; break;
7617 case LINESTYLE_BOLDDASH
: pUnderlineValue
= "dashedHeavy"; break;
7618 case LINESTYLE_LONGDASH
: pUnderlineValue
= "dashLongHeavy"; break;
7619 case LINESTYLE_BOLDLONGDASH
: pUnderlineValue
= "dashLongHeavy"; break;
7620 case LINESTYLE_BOLDDASHDOT
: pUnderlineValue
= "dashDotHeavy"; break;
7621 case LINESTYLE_BOLDDASHDOTDOT
: pUnderlineValue
= "dashDotDotHeavy"; break;
7622 case LINESTYLE_BOLDWAVE
: pUnderlineValue
= "wavyHeavy"; break;
7623 case LINESTYLE_DOUBLEWAVE
: pUnderlineValue
= "wavyDouble"; break;
7624 case LINESTYLE_NONE
: // fall through
7625 default: pUnderlineValue
= "none"; break;
7628 Color aUnderlineColor
= rUnderline
.GetColor();
7629 bool bUnderlineHasColor
= aUnderlineColor
.GetTransparency() == 0;
7630 if (bUnderlineHasColor
)
7632 // Underline has a color
7633 m_pSerializer
->singleElementNS( XML_w
, XML_u
,
7634 FSNS( XML_w
, XML_val
), pUnderlineValue
,
7635 FSNS( XML_w
, XML_color
), msfilter::util::ConvertColor(aUnderlineColor
) );
7639 // Underline has no color
7640 m_pSerializer
->singleElementNS(XML_w
, XML_u
, FSNS(XML_w
, XML_val
), pUnderlineValue
);
7644 void DocxAttributeOutput::CharWeight( const SvxWeightItem
& rWeight
)
7646 if ( rWeight
.GetWeight() == WEIGHT_BOLD
)
7647 m_pSerializer
->singleElementNS(XML_w
, XML_b
);
7649 m_pSerializer
->singleElementNS(XML_w
, XML_b
, FSNS(XML_w
, XML_val
), "false");
7652 void DocxAttributeOutput::CharAutoKern( const SvxAutoKernItem
& rAutoKern
)
7654 // auto kerning is bound to a minimum font size in Word - but is just a boolean in Writer :-(
7655 // kerning is based on half-point sizes, so 2 enables kerning for fontsize 1pt or higher. (1 is treated as size 12, and 0 is treated as disabled.)
7656 const OString sFontSize
= OString::number( static_cast<sal_uInt32
>(rAutoKern
.GetValue()) * 2 );
7657 m_pSerializer
->singleElementNS(XML_w
, XML_kern
, FSNS(XML_w
, XML_val
), sFontSize
);
7660 void DocxAttributeOutput::CharAnimatedText( const SvxBlinkItem
& rBlink
)
7662 if ( rBlink
.GetValue() )
7663 m_pSerializer
->singleElementNS(XML_w
, XML_effect
, FSNS(XML_w
, XML_val
), "blinkBackground");
7665 m_pSerializer
->singleElementNS(XML_w
, XML_effect
, FSNS(XML_w
, XML_val
), "none");
7668 #define MSWORD_CH_SHADING_FILL "FFFFFF" // The attribute w:fill of w:shd, for MS-Word's character shading,
7669 #define MSWORD_CH_SHADING_COLOR "auto" // The attribute w:color of w:shd, for MS-Word's character shading,
7670 #define MSWORD_CH_SHADING_VAL "pct15" // The attribute w:value of w:shd, for MS-Word's character shading,
7672 void DocxAttributeOutput::CharBackground( const SvxBrushItem
& rBrush
)
7674 // Check if the brush shading pattern is 'PCT15'. If so - write it back to the DOCX
7675 if (rBrush
.GetShadingValue() == ShadingPattern::PCT15
)
7677 m_pSerializer
->singleElementNS( XML_w
, XML_shd
,
7678 FSNS( XML_w
, XML_val
), MSWORD_CH_SHADING_VAL
,
7679 FSNS( XML_w
, XML_color
), MSWORD_CH_SHADING_COLOR
,
7680 FSNS( XML_w
, XML_fill
), MSWORD_CH_SHADING_FILL
);
7684 m_pSerializer
->singleElementNS( XML_w
, XML_shd
,
7685 FSNS( XML_w
, XML_fill
), msfilter::util::ConvertColor(rBrush
.GetColor()),
7686 FSNS( XML_w
, XML_val
), "clear" );
7690 void DocxAttributeOutput::CharFontCJK( const SvxFontItem
& rFont
)
7692 if (m_pFontsAttrList
&& m_pFontsAttrList
->hasAttribute(FSNS(XML_w
, XML_eastAsia
)))
7694 // tdf#38778: do to fields output into DOC the font could be added before and after field declaration
7695 // that all sub runs of the field will have correct font inside.
7696 // For DOCX we should do not add the same font information twice in the same node
7700 const OUString
& sFontName(rFont
.GetFamilyName());
7701 OString sFontNameUtf8
= OUStringToOString(sFontName
, RTL_TEXTENCODING_UTF8
);
7702 AddToAttrList( m_pFontsAttrList
, FSNS( XML_w
, XML_eastAsia
), sFontNameUtf8
.getStr() );
7705 void DocxAttributeOutput::CharPostureCJK( const SvxPostureItem
& rPosture
)
7707 if ( rPosture
.GetPosture() != ITALIC_NONE
)
7708 m_pSerializer
->singleElementNS(XML_w
, XML_i
);
7710 m_pSerializer
->singleElementNS(XML_w
, XML_i
, FSNS(XML_w
, XML_val
), "false");
7713 void DocxAttributeOutput::CharWeightCJK( const SvxWeightItem
& rWeight
)
7715 if ( rWeight
.GetWeight() == WEIGHT_BOLD
)
7716 m_pSerializer
->singleElementNS(XML_w
, XML_b
);
7718 m_pSerializer
->singleElementNS(XML_w
, XML_b
, FSNS(XML_w
, XML_val
), "false");
7721 void DocxAttributeOutput::CharFontCTL( const SvxFontItem
& rFont
)
7723 if (m_pFontsAttrList
&& m_pFontsAttrList
->hasAttribute(FSNS(XML_w
, XML_cs
)))
7725 // tdf#38778: do to fields output into DOC the font could be added before and after field declaration
7726 // that all sub runs of the field will have correct font inside.
7727 // For DOCX we should do not add the same font information twice in the same node
7731 const OUString
& sFontName(rFont
.GetFamilyName());
7732 OString sFontNameUtf8
= OUStringToOString(sFontName
, RTL_TEXTENCODING_UTF8
);
7733 AddToAttrList( m_pFontsAttrList
, FSNS( XML_w
, XML_cs
), sFontNameUtf8
.getStr() );
7736 void DocxAttributeOutput::CharPostureCTL( const SvxPostureItem
& rPosture
)
7738 if ( rPosture
.GetPosture() != ITALIC_NONE
)
7739 m_pSerializer
->singleElementNS(XML_w
, XML_iCs
);
7741 m_pSerializer
->singleElementNS(XML_w
, XML_iCs
, FSNS(XML_w
, XML_val
), "false");
7744 void DocxAttributeOutput::CharWeightCTL( const SvxWeightItem
& rWeight
)
7746 if ( rWeight
.GetWeight() == WEIGHT_BOLD
)
7747 m_pSerializer
->singleElementNS(XML_w
, XML_bCs
);
7749 m_pSerializer
->singleElementNS(XML_w
, XML_bCs
, FSNS(XML_w
, XML_val
), "false");
7752 void DocxAttributeOutput::CharBidiRTL( const SfxPoolItem
& )
7756 void DocxAttributeOutput::CharIdctHint( const SfxPoolItem
& )
7760 void DocxAttributeOutput::CharRotate( const SvxCharRotateItem
& rRotate
)
7763 if ( !rRotate
.GetValue())
7766 AddToAttrList( m_pEastAsianLayoutAttrList
, FSNS( XML_w
, XML_vert
), "true" );
7768 if (rRotate
.IsFitToLine())
7769 AddToAttrList( m_pEastAsianLayoutAttrList
, FSNS( XML_w
, XML_vertCompress
), "true" );
7772 void DocxAttributeOutput::CharEmphasisMark( const SvxEmphasisMarkItem
& rEmphasisMark
)
7774 const char *pEmphasis
;
7775 const FontEmphasisMark v
= rEmphasisMark
.GetEmphasisMark();
7777 if (v
== (FontEmphasisMark::Dot
| FontEmphasisMark::PosAbove
))
7779 else if (v
== (FontEmphasisMark::Accent
| FontEmphasisMark::PosAbove
))
7780 pEmphasis
= "comma";
7781 else if (v
== (FontEmphasisMark::Circle
| FontEmphasisMark::PosAbove
))
7782 pEmphasis
= "circle";
7783 else if (v
== (FontEmphasisMark::Dot
|FontEmphasisMark::PosBelow
))
7784 pEmphasis
= "underDot";
7788 m_pSerializer
->singleElementNS(XML_w
, XML_em
, FSNS(XML_w
, XML_val
), pEmphasis
);
7791 void DocxAttributeOutput::CharTwoLines( const SvxTwoLinesItem
& rTwoLines
)
7793 if ( !rTwoLines
.GetValue() )
7796 AddToAttrList( m_pEastAsianLayoutAttrList
, FSNS( XML_w
, XML_combine
), "true" );
7798 sal_Unicode cStart
= rTwoLines
.GetStartBracket();
7799 sal_Unicode cEnd
= rTwoLines
.GetEndBracket();
7801 if (!cStart
&& !cEnd
)
7805 if ((cStart
== '{') || (cEnd
== '}'))
7806 sBracket
= const_cast<char *>("curly");
7807 else if ((cStart
== '<') || (cEnd
== '>'))
7808 sBracket
= const_cast<char *>("angle");
7809 else if ((cStart
== '[') || (cEnd
== ']'))
7810 sBracket
= const_cast<char *>("square");
7812 sBracket
= const_cast<char *>("round");
7813 AddToAttrList( m_pEastAsianLayoutAttrList
, FSNS( XML_w
, XML_combineBrackets
), sBracket
.getStr() );
7816 void DocxAttributeOutput::CharScaleWidth( const SvxCharScaleWidthItem
& rScaleWidth
)
7818 // Clamp CharScaleWidth to OOXML limits ([1..600])
7819 const sal_Int16
nScaleWidth( std::max
<sal_Int16
>( 1,
7820 std::min
<sal_Int16
>( rScaleWidth
.GetValue(), 600 ) ) );
7821 m_pSerializer
->singleElementNS( XML_w
, XML_w
,
7822 FSNS( XML_w
, XML_val
), OString::number(nScaleWidth
) );
7825 void DocxAttributeOutput::CharRelief( const SvxCharReliefItem
& rRelief
)
7827 switch ( rRelief
.GetValue() )
7829 case FontRelief::Embossed
:
7830 m_pSerializer
->singleElementNS(XML_w
, XML_emboss
);
7832 case FontRelief::Engraved
:
7833 m_pSerializer
->singleElementNS(XML_w
, XML_imprint
);
7836 m_pSerializer
->singleElementNS(XML_w
, XML_emboss
, FSNS(XML_w
, XML_val
), "false");
7837 m_pSerializer
->singleElementNS(XML_w
, XML_imprint
, FSNS(XML_w
, XML_val
), "false");
7842 void DocxAttributeOutput::CharHidden( const SvxCharHiddenItem
& rHidden
)
7844 if ( rHidden
.GetValue() )
7845 m_pSerializer
->singleElementNS(XML_w
, XML_vanish
);
7847 m_pSerializer
->singleElementNS(XML_w
, XML_vanish
, FSNS(XML_w
, XML_val
), "false");
7850 void DocxAttributeOutput::CharBorder(
7851 const SvxBorderLine
* pAllBorder
, const sal_uInt16 nDist
, const bool bShadow
)
7853 css::table::BorderLine2 rStyleBorder
;
7854 const SvxBoxItem
* pInherited
= nullptr;
7855 if ( GetExport().m_bStyDef
&& GetExport().m_pCurrentStyle
&& GetExport().m_pCurrentStyle
->DerivedFrom() )
7856 pInherited
= GetExport().m_pCurrentStyle
->DerivedFrom()->GetAttrSet().GetItem
<SvxBoxItem
>(RES_CHRATR_BOX
);
7857 else if ( m_rExport
.m_pChpIter
) // incredibly undocumented, but this is the character-style info, right?
7858 pInherited
= static_cast<const SvxBoxItem
*>(GetExport().m_pChpIter
->HasTextItem(RES_CHRATR_BOX
));
7861 rStyleBorder
= SvxBoxItem::SvxLineToLine(pInherited
->GetRight(), false);
7863 impl_borderLine( m_pSerializer
, XML_bdr
, pAllBorder
, nDist
, bShadow
, &rStyleBorder
);
7866 void DocxAttributeOutput::CharHighlight( const SvxBrushItem
& rHighlight
)
7868 const OString sColor
= TransHighlightColor( msfilter::util::TransColToIco(rHighlight
.GetColor()) );
7869 if ( !sColor
.isEmpty() )
7871 m_pSerializer
->singleElementNS(XML_w
, XML_highlight
, FSNS(XML_w
, XML_val
), sColor
);
7875 void DocxAttributeOutput::TextINetFormat( const SwFormatINetFormat
& rLink
)
7877 OString aStyleId
= MSWordStyles::CreateStyleId(rLink
.GetINetFormat());
7878 if (!aStyleId
.isEmpty() && !aStyleId
.equalsIgnoreAsciiCase("DefaultStyle"))
7879 m_pSerializer
->singleElementNS(XML_w
, XML_rStyle
, FSNS(XML_w
, XML_val
), aStyleId
);
7882 void DocxAttributeOutput::TextCharFormat( const SwFormatCharFormat
& rCharFormat
)
7884 OString
aStyleId(m_rExport
.m_pStyles
->GetStyleId(m_rExport
.GetId(rCharFormat
.GetCharFormat())));
7886 m_pSerializer
->singleElementNS(XML_w
, XML_rStyle
, FSNS(XML_w
, XML_val
), aStyleId
);
7889 void DocxAttributeOutput::RefField( const SwField
& rField
, const OUString
& rRef
)
7891 SwFieldIds nType
= rField
.GetTyp( )->Which( );
7892 if ( nType
== SwFieldIds::GetExp
)
7894 OUString sCmd
= FieldString( ww::eREF
) +
7895 "\"" + rRef
+ "\" ";
7897 m_rExport
.OutputField( &rField
, ww::eREF
, sCmd
);
7900 // There is nothing to do here for the set fields
7903 void DocxAttributeOutput::HiddenField(const SwField
& rField
)
7905 auto eSubType
= static_cast<SwFieldTypesEnum
>(rField
.GetSubType());
7906 if (eSubType
== SwFieldTypesEnum::ConditionalText
)
7908 OUString aCond
= rField
.GetPar1();
7909 OUString aTrueFalse
= rField
.GetPar2();
7910 sal_Int32 nPos
= aTrueFalse
.indexOf('|');
7919 aTrue
= aTrueFalse
.subView(0, nPos
);
7920 aFalse
= aTrueFalse
.subView(nPos
+ 1);
7922 OUString aCmd
= FieldString(ww::eIF
) + aCond
+ " \"" + aTrue
+ "\" \"" + aFalse
+ "\"";
7923 m_rExport
.OutputField(&rField
, ww::eIF
, aCmd
);
7927 SAL_INFO("sw.ww8", "TODO DocxAttributeOutput::HiddenField()" );
7930 void DocxAttributeOutput::PostitField( const SwField
* pField
)
7932 assert( dynamic_cast< const SwPostItField
* >( pField
));
7933 const SwPostItField
* pPostItField
= static_cast<const SwPostItField
*>(pField
);
7934 OString aName
= OUStringToOString(pPostItField
->GetName(), RTL_TEXTENCODING_UTF8
);
7936 std::map
< OString
, sal_Int32
>::iterator it
= m_rOpenedAnnotationMarksIds
.find(aName
);
7937 if (it
!= m_rOpenedAnnotationMarksIds
.end())
7938 // If the postit field has an annotation mark associated, we already have an id.
7941 // Otherwise get a new one.
7942 nId
= m_nNextAnnotationMarkId
++;
7943 m_postitFields
.emplace_back(pPostItField
, nId
);
7946 void DocxAttributeOutput::WritePostitFieldReference()
7948 while( m_postitFieldsMaxId
< m_postitFields
.size())
7950 OString idstr
= OString::number(m_postitFields
[m_postitFieldsMaxId
].second
);
7952 // In case this file is inside annotation marks, we want to write the
7953 // comment reference after the annotation mark is closed, not here.
7954 OString idname
= OUStringToOString(m_postitFields
[m_postitFieldsMaxId
].first
->GetName(), RTL_TEXTENCODING_UTF8
);
7955 std::map
< OString
, sal_Int32
>::iterator it
= m_rOpenedAnnotationMarksIds
.find( idname
);
7956 if ( it
== m_rOpenedAnnotationMarksIds
.end( ) )
7957 m_pSerializer
->singleElementNS(XML_w
, XML_commentReference
, FSNS(XML_w
, XML_id
), idstr
);
7958 ++m_postitFieldsMaxId
;
7962 void DocxAttributeOutput::WritePostitFields()
7964 for (const auto& rPair
: m_postitFields
)
7966 OString idstr
= OString::number( rPair
.second
);
7967 const SwPostItField
* f
= rPair
.first
;
7968 m_pSerializer
->startElementNS( XML_w
, XML_comment
, FSNS( XML_w
, XML_id
), idstr
,
7969 FSNS( XML_w
, XML_author
), f
->GetPar1(),
7970 FSNS( XML_w
, XML_date
), DateTimeToOString(f
->GetDateTime()),
7971 FSNS( XML_w
, XML_initials
), f
->GetInitials() );
7973 if (f
->GetTextObject() != nullptr)
7976 GetExport().WriteOutliner(*f
->GetTextObject(), TXT_ATN
);
7980 // just plain text - eg. when the field was created via the
7981 // .uno:InsertAnnotation API
7982 m_pSerializer
->startElementNS(XML_w
, XML_p
);
7983 m_pSerializer
->startElementNS(XML_w
, XML_r
);
7984 RunText(f
->GetText());
7985 m_pSerializer
->endElementNS(XML_w
, XML_r
);
7986 m_pSerializer
->endElementNS(XML_w
, XML_p
);
7989 m_pSerializer
->endElementNS( XML_w
, XML_comment
);
7993 bool DocxAttributeOutput::DropdownField( const SwField
* pField
)
7995 ww::eField eType
= ww::eFORMDROPDOWN
;
7996 OUString sCmd
= FieldString( eType
);
7997 GetExport( ).OutputField( pField
, eType
, sCmd
);
8002 bool DocxAttributeOutput::PlaceholderField( const SwField
* pField
)
8004 assert( pendingPlaceholder
== nullptr );
8005 pendingPlaceholder
= pField
;
8006 return false; // do not expand
8009 void DocxAttributeOutput::WritePendingPlaceholder()
8011 if( pendingPlaceholder
== nullptr )
8013 const SwField
* pField
= pendingPlaceholder
;
8014 pendingPlaceholder
= nullptr;
8015 m_pSerializer
->startElementNS(XML_w
, XML_sdt
);
8016 m_pSerializer
->startElementNS(XML_w
, XML_sdtPr
);
8017 if( !pField
->GetPar2().isEmpty())
8018 m_pSerializer
->singleElementNS(XML_w
, XML_alias
, FSNS(XML_w
, XML_val
), pField
->GetPar2());
8019 m_pSerializer
->singleElementNS(XML_w
, XML_temporary
);
8020 m_pSerializer
->singleElementNS(XML_w
, XML_showingPlcHdr
);
8021 m_pSerializer
->singleElementNS(XML_w
, XML_text
);
8022 m_pSerializer
->endElementNS( XML_w
, XML_sdtPr
);
8023 m_pSerializer
->startElementNS(XML_w
, XML_sdtContent
);
8024 m_pSerializer
->startElementNS(XML_w
, XML_r
);
8025 RunText( pField
->GetPar1());
8026 m_pSerializer
->endElementNS( XML_w
, XML_r
);
8027 m_pSerializer
->endElementNS( XML_w
, XML_sdtContent
);
8028 m_pSerializer
->endElementNS( XML_w
, XML_sdt
);
8031 void DocxAttributeOutput::SetField( const SwField
& rField
, ww::eField eType
, const OUString
& rCmd
)
8033 // field bookmarks are handled in the EndRun method
8034 GetExport().OutputField(&rField
, eType
, rCmd
);
8037 void DocxAttributeOutput::WriteExpand( const SwField
* pField
)
8039 // Will be written in the next End Run
8040 m_rExport
.OutputField( pField
, ww::eUNKNOWN
, OUString() );
8043 void DocxAttributeOutput::WriteField_Impl( const SwField
* pField
, ww::eField eType
, const OUString
& rFieldCmd
, FieldFlags nMode
)
8045 if (m_bPreventDoubleFieldsHandling
)
8048 struct FieldInfos infos
;
8050 infos
.pField
= pField
->CopyField();
8051 infos
.sCmd
= rFieldCmd
;
8052 infos
.eType
= eType
;
8053 infos
.bClose
= bool(FieldFlags::Close
& nMode
);
8054 infos
.bSep
= bool(FieldFlags::CmdEnd
& nMode
);
8055 infos
.bOpen
= bool(FieldFlags::Start
& nMode
);
8056 m_Fields
.push_back( infos
);
8061 SwFieldIds nType
= pField
->GetTyp( )->Which( );
8062 sal_uInt16 nSubType
= pField
->GetSubType();
8064 // TODO Any other field types here ?
8065 if ( ( nType
== SwFieldIds::SetExp
) && ( nSubType
& nsSwGetSetExpType::GSE_STRING
) )
8067 const SwSetExpField
*pSet
= static_cast<const SwSetExpField
*>( pField
);
8068 m_sFieldBkm
= pSet
->GetPar1( );
8070 else if ( nType
== SwFieldIds::Dropdown
)
8072 const SwDropDownField
* pDropDown
= static_cast<const SwDropDownField
*>( pField
);
8073 m_sFieldBkm
= pDropDown
->GetName( );
8077 void DocxAttributeOutput::WriteFormData_Impl( const ::sw::mark::IFieldmark
& rFieldmark
)
8079 if ( !m_Fields
.empty() )
8080 m_Fields
.begin()->pFieldmark
= &rFieldmark
;
8083 void DocxAttributeOutput::WriteBookmarks_Impl( std::vector
< OUString
>& rStarts
, std::vector
< OUString
>& rEnds
)
8085 for ( const OUString
& name
: rStarts
)
8087 if (name
.startsWith("permission-for-group:") ||
8088 name
.startsWith("permission-for-user:"))
8090 m_rPermissionsStart
.push_back(name
);
8094 m_rBookmarksStart
.push_back(name
);
8099 for ( const OUString
& name
: rEnds
)
8101 if (name
.startsWith("permission-for-group:") ||
8102 name
.startsWith("permission-for-user:"))
8104 m_rPermissionsEnd
.push_back(name
);
8108 m_rBookmarksEnd
.push_back(name
);
8114 void DocxAttributeOutput::WriteFinalBookmarks_Impl( std::vector
< OUString
>& rStarts
, std::vector
< OUString
>& rEnds
)
8116 for ( const OUString
& name
: rStarts
)
8118 if (name
.startsWith("permission-for-group:") ||
8119 name
.startsWith("permission-for-user:"))
8121 m_rPermissionsStart
.push_back(name
);
8125 m_rFinalBookmarksStart
.push_back(name
);
8130 for ( const OUString
& name
: rEnds
)
8132 if (name
.startsWith("permission-for-group:") ||
8133 name
.startsWith("permission-for-user:"))
8135 m_rPermissionsEnd
.push_back(name
);
8139 m_rFinalBookmarksEnd
.push_back(name
);
8145 void DocxAttributeOutput::WriteAnnotationMarks_Impl( std::vector
< OUString
>& rStarts
,
8146 std::vector
< OUString
>& rEnds
)
8148 for ( const auto & rAnnotationName
: rStarts
)
8150 OString rName
= OUStringToOString(rAnnotationName
, RTL_TEXTENCODING_UTF8
).getStr( );
8151 m_rAnnotationMarksStart
.push_back( rName
);
8155 for ( const auto & rAnnotationName
: rEnds
)
8157 OString rName
= OUStringToOString( rAnnotationName
, RTL_TEXTENCODING_UTF8
).getStr( );
8158 m_rAnnotationMarksEnd
.push_back( rName
);
8163 void DocxAttributeOutput::TextFootnote_Impl( const SwFormatFootnote
& rFootnote
)
8165 const SwEndNoteInfo
& rInfo
= rFootnote
.IsEndNote()?
8166 m_rExport
.m_rDoc
.GetEndNoteInfo(): m_rExport
.m_rDoc
.GetFootnoteInfo();
8168 // footnote/endnote run properties
8169 const SwCharFormat
* pCharFormat
= rInfo
.GetAnchorCharFormat( m_rExport
.m_rDoc
);
8171 OString
aStyleId(m_rExport
.m_pStyles
->GetStyleId(m_rExport
.GetId(pCharFormat
)));
8173 m_pSerializer
->singleElementNS(XML_w
, XML_rStyle
, FSNS(XML_w
, XML_val
), aStyleId
);
8175 // remember the footnote/endnote to
8176 // 1) write the footnoteReference/endnoteReference in EndRunProperties()
8177 // 2) be able to dump them all to footnotes.xml/endnotes.xml
8178 if ( !rFootnote
.IsEndNote() && m_rExport
.m_rDoc
.GetFootnoteInfo().m_ePos
!= FTNPOS_CHAPTER
)
8179 m_pFootnotesList
->add( rFootnote
);
8181 m_pEndnotesList
->add( rFootnote
);
8184 void DocxAttributeOutput::FootnoteEndnoteReference()
8187 const SwFormatFootnote
*pFootnote
= m_pFootnotesList
->getCurrent( nId
);
8188 sal_Int32 nToken
= XML_footnoteReference
;
8190 // both cannot be set at the same time - if they are, it's a bug
8193 pFootnote
= m_pEndnotesList
->getCurrent( nId
);
8194 nToken
= XML_endnoteReference
;
8201 if ( pFootnote
->GetNumStr().isEmpty() )
8204 m_pSerializer
->singleElementNS(XML_w
, nToken
, FSNS(XML_w
, XML_id
), OString::number(nId
));
8209 m_pSerializer
->singleElementNS( XML_w
, nToken
,
8210 FSNS( XML_w
, XML_customMarkFollows
), "1",
8211 FSNS( XML_w
, XML_id
), OString::number(nId
) );
8213 RunText( pFootnote
->GetNumStr() );
8217 static void WriteFootnoteSeparatorHeight(
8218 ::sax_fastparser::FSHelperPtr
const& pSerializer
, SwTwips
const nHeight
)
8220 // try to get the height by setting font size of the paragraph
8223 pSerializer
->startElementNS(XML_w
, XML_pPr
);
8224 pSerializer
->startElementNS(XML_w
, XML_rPr
);
8225 pSerializer
->singleElementNS(XML_w
, XML_sz
, FSNS(XML_w
, XML_val
),
8226 OString::number((nHeight
+ 5) / 10));
8227 pSerializer
->endElementNS(XML_w
, XML_rPr
);
8228 pSerializer
->endElementNS(XML_w
, XML_pPr
);
8232 void DocxAttributeOutput::FootnotesEndnotes( bool bFootnotes
)
8234 const FootnotesVector
& rVector
= bFootnotes
? m_pFootnotesList
->getVector(): m_pEndnotesList
->getVector();
8236 sal_Int32 nBody
= bFootnotes
? XML_footnotes
: XML_endnotes
;
8237 sal_Int32 nItem
= bFootnotes
? XML_footnote
: XML_endnote
;
8239 m_pSerializer
->startElementNS( XML_w
, nBody
, m_rExport
.MainXmlNamespaces() );
8241 sal_Int32 nIndex
= 0;
8244 // note: can only be defined for the whole document, not per section
8245 m_pSerializer
->startElementNS( XML_w
, nItem
,
8246 FSNS( XML_w
, XML_id
), OString::number(nIndex
++),
8247 FSNS( XML_w
, XML_type
), "separator" );
8248 m_pSerializer
->startElementNS(XML_w
, XML_p
);
8250 bool bSeparator
= true;
8254 const SwPageFootnoteInfo
& rFootnoteInfo
= m_rExport
.m_rDoc
.GetPageDesc(0).GetFootnoteInfo();
8255 // Request separator only if both width and thickness are non-zero.
8256 bSeparator
= rFootnoteInfo
.GetLineStyle() != SvxBorderLineStyle::NONE
8257 && rFootnoteInfo
.GetLineWidth() > 0
8258 && double(rFootnoteInfo
.GetWidth()) > 0;
8259 nHeight
= sw::FootnoteSeparatorHeight(rFootnoteInfo
);
8262 WriteFootnoteSeparatorHeight(m_pSerializer
, nHeight
);
8264 m_pSerializer
->startElementNS(XML_w
, XML_r
);
8266 m_pSerializer
->singleElementNS(XML_w
, XML_separator
);
8267 m_pSerializer
->endElementNS( XML_w
, XML_r
);
8268 m_pSerializer
->endElementNS( XML_w
, XML_p
);
8269 m_pSerializer
->endElementNS( XML_w
, nItem
);
8272 m_pSerializer
->startElementNS( XML_w
, nItem
,
8273 FSNS( XML_w
, XML_id
), OString::number(nIndex
++),
8274 FSNS( XML_w
, XML_type
), "continuationSeparator" );
8275 m_pSerializer
->startElementNS(XML_w
, XML_p
);
8277 WriteFootnoteSeparatorHeight(m_pSerializer
, nHeight
);
8279 m_pSerializer
->startElementNS(XML_w
, XML_r
);
8282 m_pSerializer
->singleElementNS(XML_w
, XML_continuationSeparator
);
8284 m_pSerializer
->endElementNS( XML_w
, XML_r
);
8285 m_pSerializer
->endElementNS( XML_w
, XML_p
);
8286 m_pSerializer
->endElementNS( XML_w
, nItem
);
8288 // if new special ones are added, update also WriteFootnoteEndnotePr()
8290 // footnotes/endnotes themselves
8291 for ( const auto& rpItem
: rVector
)
8293 m_footnoteEndnoteRefTag
= bFootnotes
? XML_footnoteRef
: XML_endnoteRef
;
8294 m_footnoteCustomLabel
= rpItem
->GetNumStr();
8296 m_pSerializer
->startElementNS(XML_w
, nItem
, FSNS(XML_w
, XML_id
), OString::number(nIndex
));
8298 const SwNodeIndex
* pIndex
= rpItem
->GetTextFootnote()->GetStartNode();
8299 m_rExport
.WriteSpecialText( pIndex
->GetIndex() + 1,
8300 pIndex
->GetNode().EndOfSectionIndex(),
8301 bFootnotes
? TXT_FTN
: TXT_EDN
);
8303 m_pSerializer
->endElementNS( XML_w
, nItem
);
8307 m_pSerializer
->endElementNS( XML_w
, nBody
);
8311 void DocxAttributeOutput::WriteFootnoteEndnotePr( ::sax_fastparser::FSHelperPtr
const & fs
, int tag
,
8312 const SwEndNoteInfo
& info
, int listtag
)
8314 fs
->startElementNS(XML_w
, tag
);
8315 const char* fmt
= nullptr;
8316 switch( info
.m_aFormat
.GetNumberingType())
8318 case SVX_NUM_CHARS_UPPER_LETTER_N
: // fall through, map to upper letters
8319 case SVX_NUM_CHARS_UPPER_LETTER
:
8320 fmt
= "upperLetter";
8322 case SVX_NUM_CHARS_LOWER_LETTER_N
: // fall through, map to lower letters
8323 case SVX_NUM_CHARS_LOWER_LETTER
:
8324 fmt
= "lowerLetter";
8326 case SVX_NUM_ROMAN_UPPER
:
8329 case SVX_NUM_ROMAN_LOWER
:
8332 case SVX_NUM_ARABIC
:
8335 case SVX_NUM_NUMBER_NONE
:
8338 case SVX_NUM_CHAR_SPECIAL
:
8341 case SVX_NUM_SYMBOL_CHICAGO
:
8344 case SVX_NUM_ARABIC_ZERO
:
8345 fmt
= "decimalZero";
8347 case SVX_NUM_PAGEDESC
:
8348 case SVX_NUM_BITMAP
:
8352 if( fmt
!= nullptr )
8353 fs
->singleElementNS(XML_w
, XML_numFmt
, FSNS(XML_w
, XML_val
), fmt
);
8354 if( info
.m_nFootnoteOffset
!= 0 )
8355 fs
->singleElementNS( XML_w
, XML_numStart
, FSNS( XML_w
, XML_val
),
8356 OString::number(info
.m_nFootnoteOffset
+ 1) );
8358 const SwFootnoteInfo
* pFootnoteInfo
= dynamic_cast<const SwFootnoteInfo
*>(&info
);
8361 switch( pFootnoteInfo
->m_eNum
)
8363 case FTNNUM_PAGE
: fmt
= "eachPage"; break;
8364 case FTNNUM_CHAPTER
: fmt
= "eachSect"; break;
8365 default: fmt
= nullptr; break;
8367 if( fmt
!= nullptr )
8368 fs
->singleElementNS(XML_w
, XML_numRestart
, FSNS(XML_w
, XML_val
), fmt
);
8371 if( listtag
!= 0 ) // we are writing to settings.xml, write also special footnote/endnote list
8372 { // there are currently only two hardcoded ones ( see FootnotesEndnotes())
8373 fs
->singleElementNS(XML_w
, listtag
, FSNS(XML_w
, XML_id
), "0");
8374 fs
->singleElementNS(XML_w
, listtag
, FSNS(XML_w
, XML_id
), "1");
8376 fs
->endElementNS( XML_w
, tag
);
8379 void DocxAttributeOutput::SectFootnoteEndnotePr()
8382 WriteFootnoteEndnotePr( m_pSerializer
, XML_footnotePr
, m_rExport
.m_rDoc
.GetFootnoteInfo(), 0 );
8384 WriteFootnoteEndnotePr( m_pSerializer
, XML_endnotePr
, m_rExport
.m_rDoc
.GetEndNoteInfo(), 0 );
8387 void DocxAttributeOutput::ParaLineSpacing_Impl( short nSpace
, short nMulti
)
8391 AddToAttrList( m_pParagraphSpacingAttrList
, 2,
8392 FSNS( XML_w
, XML_lineRule
), "exact",
8393 FSNS( XML_w
, XML_line
), OString::number( -nSpace
).getStr() );
8395 else if( nSpace
> 0 && nMulti
)
8397 AddToAttrList( m_pParagraphSpacingAttrList
, 2,
8398 FSNS( XML_w
, XML_lineRule
), "auto",
8399 FSNS( XML_w
, XML_line
), OString::number( nSpace
).getStr() );
8403 AddToAttrList( m_pParagraphSpacingAttrList
, 2,
8404 FSNS( XML_w
, XML_lineRule
), "atLeast",
8405 FSNS( XML_w
, XML_line
), OString::number( nSpace
).getStr() );
8409 void DocxAttributeOutput::ParaAdjust( const SvxAdjustItem
& rAdjust
)
8411 const char *pAdjustString
;
8413 bool bEcma
= GetExport().GetFilter().getVersion( ) == oox::core::ECMA_DIALECT
;
8415 const SfxItemSet
* pItems
= GetExport().GetCurItemSet();
8416 const SvxFrameDirectionItem
* rFrameDir
= pItems
?
8417 pItems
->GetItem( RES_FRAMEDIR
) : nullptr;
8419 SvxFrameDirection nDir
= SvxFrameDirection::Environment
;
8420 if( rFrameDir
!= nullptr )
8421 nDir
= rFrameDir
->GetValue();
8422 if ( nDir
== SvxFrameDirection::Environment
)
8423 nDir
= GetExport( ).GetDefaultFrameDirection( );
8424 bool bRtl
= ( nDir
== SvxFrameDirection::Horizontal_RL_TB
);
8426 switch ( rAdjust
.GetAdjust() )
8428 case SvxAdjust::Left
:
8432 pAdjustString
= "right";
8434 pAdjustString
= "left";
8437 pAdjustString
= "end";
8439 pAdjustString
= "start";
8441 case SvxAdjust::Right
:
8445 pAdjustString
= "left";
8447 pAdjustString
= "right";
8450 pAdjustString
= "start";
8452 pAdjustString
= "end";
8454 case SvxAdjust::BlockLine
:
8455 case SvxAdjust::Block
:
8456 if (rAdjust
.GetLastBlock() == SvxAdjust::Block
)
8457 pAdjustString
= "distribute";
8459 pAdjustString
= "both";
8461 case SvxAdjust::Center
:
8462 pAdjustString
= "center";
8465 return; // not supported attribute
8467 m_pSerializer
->singleElementNS(XML_w
, XML_jc
, FSNS(XML_w
, XML_val
), pAdjustString
);
8470 void DocxAttributeOutput::ParaSplit( const SvxFormatSplitItem
& rSplit
)
8472 if (rSplit
.GetValue())
8473 m_pSerializer
->singleElementNS(XML_w
, XML_keepLines
, FSNS(XML_w
, XML_val
), "false");
8475 m_pSerializer
->singleElementNS(XML_w
, XML_keepLines
);
8478 void DocxAttributeOutput::ParaWidows( const SvxWidowsItem
& rWidows
)
8480 if (rWidows
.GetValue())
8481 m_pSerializer
->singleElementNS(XML_w
, XML_widowControl
);
8483 m_pSerializer
->singleElementNS(XML_w
, XML_widowControl
, FSNS(XML_w
, XML_val
), "false");
8486 static void impl_WriteTabElement( FSHelperPtr
const & pSerializer
,
8487 const SvxTabStop
& rTab
, tools::Long tabsOffset
)
8489 FastAttributeList
*pTabElementAttrList
= FastSerializerHelper::createAttrList();
8491 switch (rTab
.GetAdjustment())
8493 case SvxTabAdjust::Right
:
8494 pTabElementAttrList
->add( FSNS( XML_w
, XML_val
), OString( "right" ) );
8496 case SvxTabAdjust::Decimal
:
8497 pTabElementAttrList
->add( FSNS( XML_w
, XML_val
), OString( "decimal" ) );
8499 case SvxTabAdjust::Center
:
8500 pTabElementAttrList
->add( FSNS( XML_w
, XML_val
), OString( "center" ) );
8502 case SvxTabAdjust::Default
:
8503 case SvxTabAdjust::Left
:
8505 pTabElementAttrList
->add( FSNS( XML_w
, XML_val
), OString( "left" ) );
8509 // Write position according to used offset of the whole paragraph.
8510 // In DOCX, w:pos specifies the position of the current custom tab stop with respect to the current page margins.
8511 // But in ODT, zero position could be page margins or paragraph indent according to used settings.
8512 // This is handled outside of this method and provided for us in tabsOffset parameter.
8513 pTabElementAttrList
->add( FSNS( XML_w
, XML_pos
), OString::number( rTab
.GetTabPos() + tabsOffset
) );
8515 sal_Unicode cFillChar
= rTab
.GetFill();
8517 if ('.' == cFillChar
)
8518 pTabElementAttrList
->add( FSNS( XML_w
, XML_leader
), OString( "dot" ) );
8519 else if ( '-' == cFillChar
)
8520 pTabElementAttrList
->add( FSNS( XML_w
, XML_leader
), OString( "hyphen" ) );
8521 else if ( u
'\x00B7' == cFillChar
) // middle dot
8522 pTabElementAttrList
->add( FSNS( XML_w
, XML_leader
), OString( "middleDot" ) );
8523 else if ( '_' == cFillChar
)
8524 pTabElementAttrList
->add( FSNS( XML_w
, XML_leader
), OString( "underscore" ) );
8526 pTabElementAttrList
->add( FSNS( XML_w
, XML_leader
), OString( "none" ) );
8528 pSerializer
->singleElementNS(XML_w
, XML_tab
, pTabElementAttrList
);
8531 void DocxAttributeOutput::ParaTabStop( const SvxTabStopItem
& rTabStop
)
8533 const SvxTabStopItem
* pInheritedTabs
= nullptr;
8534 if ( GetExport().m_pStyAttr
)
8535 pInheritedTabs
= GetExport().m_pStyAttr
->GetItem
<SvxTabStopItem
>(RES_PARATR_TABSTOP
);
8536 else if ( GetExport().m_pCurrentStyle
&& GetExport().m_pCurrentStyle
->DerivedFrom() )
8537 pInheritedTabs
= GetExport().m_pCurrentStyle
->DerivedFrom()->GetAttrSet().GetItem
<SvxTabStopItem
>(RES_PARATR_TABSTOP
);
8538 const sal_uInt16 nInheritedTabCount
= pInheritedTabs
? pInheritedTabs
->Count() : 0;
8539 const sal_uInt16 nCount
= rTabStop
.Count();
8541 // <w:tabs> must contain at least one <w:tab>, so don't write it empty
8542 if ( !nCount
&& !nInheritedTabCount
)
8544 if( nCount
== 1 && rTabStop
[ 0 ].GetAdjustment() == SvxTabAdjust::Default
)
8546 GetExport().setDefaultTabStop( rTabStop
[ 0 ].GetTabPos());
8550 // do not output inherited tabs twice (inside styles and inside inline properties)
8551 if ( nCount
== nInheritedTabCount
&& nCount
> 0 )
8553 if ( *pInheritedTabs
== rTabStop
)
8557 m_pSerializer
->startElementNS(XML_w
, XML_tabs
);
8559 // Get offset for tabs
8560 // In DOCX, w:pos specifies the position of the current custom tab stop with respect to the current page margins.
8561 // But in ODT, zero position could be page margins or paragraph indent according to used settings.
8562 tools::Long tabsOffset
= 0;
8563 if (m_rExport
.m_rDoc
.getIDocumentSettingAccess().get(DocumentSettingId::TABS_RELATIVE_TO_INDENT
))
8564 tabsOffset
= m_rExport
.GetItem(RES_LR_SPACE
).GetTextLeft();
8566 // clear unused inherited tabs - otherwise the style will add them back in
8567 sal_Int32 nCurrTab
= 0;
8568 for ( sal_uInt16 i
= 0; i
< nInheritedTabCount
; ++i
)
8570 while ( nCurrTab
< nCount
&& rTabStop
[nCurrTab
] < pInheritedTabs
->At(i
) )
8573 if ( nCurrTab
== nCount
|| pInheritedTabs
->At(i
) < rTabStop
[nCurrTab
] )
8575 m_pSerializer
->singleElementNS( XML_w
, XML_tab
,
8576 FSNS( XML_w
, XML_val
), "clear",
8577 FSNS( XML_w
, XML_pos
), OString::number(pInheritedTabs
->At(i
).GetTabPos()) );
8581 for (sal_uInt16 i
= 0; i
< nCount
; i
++ )
8583 if( rTabStop
[i
].GetAdjustment() != SvxTabAdjust::Default
)
8584 impl_WriteTabElement( m_pSerializer
, rTabStop
[i
], tabsOffset
);
8586 GetExport().setDefaultTabStop( rTabStop
[i
].GetTabPos());
8589 m_pSerializer
->endElementNS( XML_w
, XML_tabs
);
8592 void DocxAttributeOutput::ParaHyphenZone( const SvxHyphenZoneItem
& rHyphenZone
)
8594 m_pSerializer
->singleElementNS( XML_w
, XML_suppressAutoHyphens
,
8595 FSNS( XML_w
, XML_val
), OString::boolean( !rHyphenZone
.IsHyphen() ) );
8598 void DocxAttributeOutput::ParaNumRule_Impl( const SwTextNode
* pTextNd
, sal_Int32 nLvl
, sal_Int32 nNumId
)
8600 if ( USHRT_MAX
== nNumId
)
8603 const sal_Int32 nTableSize
= m_rExport
.m_pUsedNumTable
? m_rExport
.m_pUsedNumTable
->size() : 0;
8604 const SwNumRule
* pRule
= nNumId
> 0 && nNumId
<= nTableSize
? (*m_rExport
.m_pUsedNumTable
)[nNumId
-1] : nullptr;
8605 const bool bOutlineRule
= pRule
&& pRule
->IsOutlineRule();
8607 // Do not export outline rules (Chapter Numbering) as paragraph properties, only as style properties.
8608 if ( !pTextNd
|| !bOutlineRule
)
8610 m_pSerializer
->startElementNS(XML_w
, XML_numPr
);
8611 m_pSerializer
->singleElementNS(XML_w
, XML_ilvl
,
8612 FSNS(XML_w
, XML_val
), OString::number(nLvl
));
8613 m_pSerializer
->singleElementNS(XML_w
, XML_numId
,
8614 FSNS(XML_w
, XML_val
), OString::number(nNumId
));
8615 m_pSerializer
->endElementNS( XML_w
, XML_numPr
);
8619 void DocxAttributeOutput::ParaScriptSpace( const SfxBoolItem
& rScriptSpace
)
8621 m_pSerializer
->singleElementNS( XML_w
, XML_autoSpaceDE
,
8622 FSNS( XML_w
, XML_val
), OString::boolean( rScriptSpace
.GetValue() ) );
8625 void DocxAttributeOutput::ParaHangingPunctuation( const SfxBoolItem
& rItem
)
8627 m_pSerializer
->singleElementNS( XML_w
, XML_overflowPunct
,
8628 FSNS( XML_w
, XML_val
), OString::boolean( rItem
.GetValue() ) );
8631 void DocxAttributeOutput::ParaForbiddenRules( const SfxBoolItem
& rItem
)
8633 m_pSerializer
->singleElementNS( XML_w
, XML_kinsoku
,
8634 FSNS( XML_w
, XML_val
), OString::boolean( rItem
.GetValue() ) );
8637 void DocxAttributeOutput::ParaVerticalAlign( const SvxParaVertAlignItem
& rAlign
)
8639 const char *pAlignString
;
8641 switch ( rAlign
.GetValue() )
8643 case SvxParaVertAlignItem::Align::Baseline
:
8644 pAlignString
= "baseline";
8646 case SvxParaVertAlignItem::Align::Top
:
8647 pAlignString
= "top";
8649 case SvxParaVertAlignItem::Align::Center
:
8650 pAlignString
= "center";
8652 case SvxParaVertAlignItem::Align::Bottom
:
8653 pAlignString
= "bottom";
8655 case SvxParaVertAlignItem::Align::Automatic
:
8656 pAlignString
= "auto";
8659 return; // not supported attribute
8661 m_pSerializer
->singleElementNS(XML_w
, XML_textAlignment
, FSNS(XML_w
, XML_val
), pAlignString
);
8664 void DocxAttributeOutput::ParaSnapToGrid( const SvxParaGridItem
& rGrid
)
8666 m_pSerializer
->singleElementNS( XML_w
, XML_snapToGrid
,
8667 FSNS( XML_w
, XML_val
), OString::boolean( rGrid
.GetValue() ) );
8670 void DocxAttributeOutput::FormatFrameSize( const SwFormatFrameSize
& rSize
)
8672 if (m_rExport
.SdrExporter().getTextFrameSyntax() && m_rExport
.SdrExporter().getFlyFrameSize())
8674 const Size
* pSize
= m_rExport
.SdrExporter().getFlyFrameSize();
8675 m_rExport
.SdrExporter().getTextFrameStyle().append(";width:").append(double(pSize
->Width()) / 20);
8676 m_rExport
.SdrExporter().getTextFrameStyle().append("pt;height:").append(double(pSize
->Height()) / 20).append("pt");
8678 else if (m_rExport
.SdrExporter().getDMLTextFrameSyntax())
8681 else if ( m_rExport
.m_bOutFlyFrameAttrs
)
8683 if ( rSize
.GetWidth() && rSize
.GetWidthSizeType() == SwFrameSize::Fixed
)
8684 AddToAttrList( m_rExport
.SdrExporter().getFlyAttrList(),
8685 FSNS( XML_w
, XML_w
), OString::number( rSize
.GetWidth( ) ).getStr() );
8687 if ( rSize
.GetHeight() )
8689 OString
sRule( "exact" );
8690 if ( rSize
.GetHeightSizeType() == SwFrameSize::Minimum
)
8691 sRule
= OString( "atLeast" );
8692 AddToAttrList( m_rExport
.SdrExporter().getFlyAttrList(), 2,
8693 FSNS( XML_w
, XML_hRule
), sRule
.getStr(),
8694 FSNS( XML_w
, XML_h
), OString::number( rSize
.GetHeight( ) ).getStr() );
8697 else if ( m_rExport
.m_bOutPageDescs
)
8699 FastAttributeList
*attrList
= FastSerializerHelper::createAttrList( );
8700 if ( m_rExport
.m_pCurrentPageDesc
->GetLandscape( ) )
8701 attrList
->add( FSNS( XML_w
, XML_orient
), "landscape" );
8703 attrList
->add( FSNS( XML_w
, XML_w
), OString::number( rSize
.GetWidth( ) ) );
8704 attrList
->add( FSNS( XML_w
, XML_h
), OString::number( rSize
.GetHeight( ) ) );
8706 XFastAttributeListRef
xAttrList( attrList
);
8709 m_pSerializer
->singleElementNS( XML_w
, XML_pgSz
, xAttrList
);
8713 void DocxAttributeOutput::FormatPaperBin( const SvxPaperBinItem
& )
8715 SAL_INFO("sw.ww8", "TODO DocxAttributeOutput::FormatPaperBin()" );
8718 void DocxAttributeOutput::FormatLRSpace( const SvxLRSpaceItem
& rLRSpace
)
8720 bool bEcma
= m_rExport
.GetFilter().getVersion( ) == oox::core::ECMA_DIALECT
;
8722 if (m_rExport
.SdrExporter().getTextFrameSyntax())
8724 m_rExport
.SdrExporter().getTextFrameStyle().append(";mso-wrap-distance-left:").append(double(rLRSpace
.GetLeft()) / 20).append("pt");
8725 m_rExport
.SdrExporter().getTextFrameStyle().append(";mso-wrap-distance-right:").append(double(rLRSpace
.GetRight()) / 20).append("pt");
8727 else if (m_rExport
.SdrExporter().getDMLTextFrameSyntax())
8730 else if ( m_rExport
.m_bOutFlyFrameAttrs
)
8732 AddToAttrList( m_rExport
.SdrExporter().getFlyAttrList(), FSNS( XML_w
, XML_hSpace
),
8734 ( rLRSpace
.GetLeft() + rLRSpace
.GetRight() ) / 2 ).getStr() );
8736 else if ( m_rExport
.m_bOutPageDescs
)
8738 m_pageMargins
.nLeft
= 0;
8739 m_pageMargins
.nRight
= 0;
8741 if ( auto pBoxItem
= static_cast<const SvxBoxItem
*>(m_rExport
.HasItem( RES_BOX
)) )
8743 m_pageMargins
.nLeft
= pBoxItem
->CalcLineSpace( SvxBoxItemLine::LEFT
, /*bEvenIfNoLine*/true );
8744 m_pageMargins
.nRight
= pBoxItem
->CalcLineSpace( SvxBoxItemLine::RIGHT
, /*bEvenIfNoLine*/true );
8747 m_pageMargins
.nLeft
+= sal::static_int_cast
<sal_uInt16
>(rLRSpace
.GetLeft());
8748 m_pageMargins
.nRight
+= sal::static_int_cast
<sal_uInt16
>(rLRSpace
.GetRight());
8750 AddToAttrList( m_pSectionSpacingAttrList
, 2,
8751 FSNS( XML_w
, XML_left
), OString::number( m_pageMargins
.nLeft
).getStr(),
8752 FSNS( XML_w
, XML_right
), OString::number( m_pageMargins
.nRight
).getStr() );
8756 FastAttributeList
*pLRSpaceAttrList
= FastSerializerHelper::createAttrList();
8757 if((0 != rLRSpace
.GetTextLeft()) || (rLRSpace
.IsExplicitZeroMarginValLeft()))
8759 pLRSpaceAttrList
->add( FSNS( XML_w
, ( bEcma
? XML_left
: XML_start
) ), OString::number( rLRSpace
.GetTextLeft() ) );
8761 if((0 != rLRSpace
.GetRight()) || (rLRSpace
.IsExplicitZeroMarginValRight()))
8763 pLRSpaceAttrList
->add( FSNS( XML_w
, ( bEcma
? XML_right
: XML_end
) ), OString::number( rLRSpace
.GetRight() ) );
8765 sal_Int32 nFirstLineAdjustment
= rLRSpace
.GetTextFirstLineOffset();
8766 if (nFirstLineAdjustment
> 0)
8767 pLRSpaceAttrList
->add( FSNS( XML_w
, XML_firstLine
), OString::number( nFirstLineAdjustment
) );
8769 pLRSpaceAttrList
->add( FSNS( XML_w
, XML_hanging
), OString::number( - nFirstLineAdjustment
) );
8770 m_pSerializer
->singleElementNS( XML_w
, XML_ind
, pLRSpaceAttrList
);
8774 void DocxAttributeOutput::FormatULSpace( const SvxULSpaceItem
& rULSpace
)
8777 if (m_rExport
.SdrExporter().getTextFrameSyntax())
8779 m_rExport
.SdrExporter().getTextFrameStyle().append(";mso-wrap-distance-top:").append(double(rULSpace
.GetUpper()) / 20).append("pt");
8780 m_rExport
.SdrExporter().getTextFrameStyle().append(";mso-wrap-distance-bottom:").append(double(rULSpace
.GetLower()) / 20).append("pt");
8782 else if (m_rExport
.SdrExporter().getDMLTextFrameSyntax())
8785 else if ( m_rExport
.m_bOutFlyFrameAttrs
)
8787 AddToAttrList( m_rExport
.SdrExporter().getFlyAttrList(), FSNS( XML_w
, XML_vSpace
),
8789 ( rULSpace
.GetLower() + rULSpace
.GetUpper() ) / 2 ).getStr() );
8791 else if (m_rExport
.m_bOutPageDescs
)
8793 OSL_ENSURE( m_rExport
.GetCurItemSet(), "Impossible" );
8794 if ( !m_rExport
.GetCurItemSet() )
8797 HdFtDistanceGlue
aDistances( *m_rExport
.GetCurItemSet() );
8799 sal_Int32 nHeader
= 0;
8800 if ( aDistances
.HasHeader() )
8801 nHeader
= sal_Int32( aDistances
.dyaHdrTop
);
8802 else if (m_rExport
.m_pFirstPageFormat
)
8804 HdFtDistanceGlue
aFirstPageDistances(m_rExport
.m_pFirstPageFormat
->GetAttrSet());
8805 if (aFirstPageDistances
.HasHeader())
8807 // The follow page style has no header, but the first page style has. In Word terms,
8808 // this means that the header margin of "the" section is coming from the first page
8810 nHeader
= sal_Int32(aFirstPageDistances
.dyaHdrTop
);
8815 m_pageMargins
.nTop
= aDistances
.dyaTop
;
8817 sal_Int32 nFooter
= 0;
8818 if ( aDistances
.HasFooter() )
8819 nFooter
= sal_Int32( aDistances
.dyaHdrBottom
);
8820 else if (m_rExport
.m_pFirstPageFormat
)
8822 HdFtDistanceGlue
aFirstPageDistances(m_rExport
.m_pFirstPageFormat
->GetAttrSet());
8823 if (aFirstPageDistances
.HasFooter())
8825 // The follow page style has no footer, but the first page style has. In Word terms,
8826 // this means that the footer margin of "the" section is coming from the first page
8828 nFooter
= sal_Int32(aFirstPageDistances
.dyaHdrBottom
);
8833 m_pageMargins
.nBottom
= aDistances
.dyaBottom
;
8835 AddToAttrList( m_pSectionSpacingAttrList
, 5,
8836 FSNS( XML_w
, XML_header
), OString::number( nHeader
).getStr(),
8837 FSNS( XML_w
, XML_top
), OString::number( m_pageMargins
.nTop
).getStr(),
8838 FSNS( XML_w
, XML_footer
), OString::number( nFooter
).getStr(),
8839 FSNS( XML_w
, XML_bottom
), OString::number( m_pageMargins
.nBottom
).getStr(),
8840 // FIXME Page Gutter is not handled ATM, setting to 0 as it's mandatory for OOXML
8841 FSNS( XML_w
, XML_gutter
), "0" );
8845 SAL_INFO("sw.ww8", "DocxAttributeOutput::FormatULSpace: setting spacing" << rULSpace
.GetUpper() );
8846 // check if before auto spacing was set during import and spacing we get from actual object is same
8847 // that we set in import. If yes just write beforeAutoSpacing tag.
8848 if (m_bParaBeforeAutoSpacing
&& m_nParaBeforeSpacing
== rULSpace
.GetUpper())
8850 AddToAttrList( m_pParagraphSpacingAttrList
,
8851 FSNS( XML_w
, XML_beforeAutospacing
), "1" );
8853 else if (m_bParaBeforeAutoSpacing
&& m_nParaBeforeSpacing
== -1)
8855 AddToAttrList( m_pParagraphSpacingAttrList
,
8856 FSNS( XML_w
, XML_beforeAutospacing
), "0" );
8857 AddToAttrList( m_pParagraphSpacingAttrList
,
8858 FSNS( XML_w
, XML_before
), OString::number( rULSpace
.GetUpper() ).getStr() );
8862 AddToAttrList( m_pParagraphSpacingAttrList
,
8863 FSNS( XML_w
, XML_before
), OString::number( rULSpace
.GetUpper() ).getStr() );
8865 m_bParaBeforeAutoSpacing
= false;
8866 // check if after auto spacing was set during import and spacing we get from actual object is same
8867 // that we set in import. If yes just write afterAutoSpacing tag.
8868 if (m_bParaAfterAutoSpacing
&& m_nParaAfterSpacing
== rULSpace
.GetLower())
8870 AddToAttrList( m_pParagraphSpacingAttrList
,
8871 FSNS( XML_w
, XML_afterAutospacing
), "1" );
8873 else if (m_bParaAfterAutoSpacing
&& m_nParaAfterSpacing
== -1)
8875 AddToAttrList( m_pParagraphSpacingAttrList
,
8876 FSNS( XML_w
, XML_afterAutospacing
), "0" );
8877 AddToAttrList( m_pParagraphSpacingAttrList
,
8878 FSNS( XML_w
, XML_after
), OString::number( rULSpace
.GetLower()).getStr() );
8882 AddToAttrList( m_pParagraphSpacingAttrList
,
8883 FSNS( XML_w
, XML_after
), OString::number( rULSpace
.GetLower()).getStr() );
8885 m_bParaAfterAutoSpacing
= false;
8887 if (rULSpace
.GetContext())
8888 m_pSerializer
->singleElementNS(XML_w
, XML_contextualSpacing
);
8894 std::unique_ptr
<FastAttributeList
> SurroundToVMLWrap(SwFormatSurround
const& rSurround
)
8896 FastAttributeList
* pAttrList(nullptr);
8899 switch (rSurround
.GetSurround())
8901 case css::text::WrapTextMode_NONE
:
8902 sType
= "topAndBottom";
8904 case css::text::WrapTextMode_PARALLEL
:
8907 case css::text::WrapTextMode_DYNAMIC
:
8911 case css::text::WrapTextMode_LEFT
:
8915 case css::text::WrapTextMode_RIGHT
:
8919 case css::text::WrapTextMode_THROUGH
:
8920 /* empty type and side means through */
8925 if (!sType
.isEmpty() || !sSide
.isEmpty())
8927 pAttrList
= FastSerializerHelper::createAttrList();
8928 if (!sType
.isEmpty())
8930 pAttrList
->add(XML_type
, sType
);
8932 if (!sSide
.isEmpty())
8934 pAttrList
->add(XML_side
, sSide
);
8937 return std::unique_ptr
<FastAttributeList
>(pAttrList
);
8942 void DocxAttributeOutput::FormatSurround( const SwFormatSurround
& rSurround
)
8944 if (m_rExport
.SdrExporter().getTextFrameSyntax())
8946 std::unique_ptr
<FastAttributeList
> pAttrList(docx::SurroundToVMLWrap(rSurround
));
8949 m_rExport
.SdrExporter().setFlyWrapAttrList(pAttrList
.release());
8952 else if (m_rExport
.SdrExporter().getDMLTextFrameSyntax())
8955 else if ( m_rExport
.m_bOutFlyFrameAttrs
)
8957 OString
sWrap( "auto" );
8958 switch ( rSurround
.GetSurround( ) )
8960 case css::text::WrapTextMode_NONE
:
8961 sWrap
= OString( "none" );
8963 case css::text::WrapTextMode_THROUGH
:
8964 sWrap
= OString( "through" );
8966 case css::text::WrapTextMode_DYNAMIC
:
8967 case css::text::WrapTextMode_PARALLEL
:
8968 case css::text::WrapTextMode_LEFT
:
8969 case css::text::WrapTextMode_RIGHT
:
8971 sWrap
= OString( "around" );
8974 AddToAttrList( m_rExport
.SdrExporter().getFlyAttrList(), FSNS( XML_w
, XML_wrap
), sWrap
.getStr() );
8978 void DocxAttributeOutput::FormatVertOrientation( const SwFormatVertOrient
& rFlyVert
)
8980 OString sAlign
= convertToOOXMLVertOrient( rFlyVert
.GetVertOrient() );
8981 OString sVAnchor
= convertToOOXMLVertOrientRel( rFlyVert
.GetRelationOrient() );
8983 if (m_rExport
.SdrExporter().getTextFrameSyntax())
8985 m_rExport
.SdrExporter().getTextFrameStyle().append(";margin-top:").append(double(rFlyVert
.GetPos()) / 20).append("pt");
8986 if ( !sAlign
.isEmpty() )
8987 m_rExport
.SdrExporter().getTextFrameStyle().append(";mso-position-vertical:").append(sAlign
);
8988 m_rExport
.SdrExporter().getTextFrameStyle().append(";mso-position-vertical-relative:").append(sVAnchor
);
8990 else if (m_rExport
.SdrExporter().getDMLTextFrameSyntax())
8993 else if ( m_rExport
.m_bOutFlyFrameAttrs
)
8995 if ( !sAlign
.isEmpty() )
8996 AddToAttrList( m_rExport
.SdrExporter().getFlyAttrList(), FSNS( XML_w
, XML_yAlign
), sAlign
.getStr() );
8998 AddToAttrList( m_rExport
.SdrExporter().getFlyAttrList(), FSNS( XML_w
, XML_y
),
8999 OString::number( rFlyVert
.GetPos() ).getStr() );
9000 AddToAttrList( m_rExport
.SdrExporter().getFlyAttrList(), FSNS( XML_w
, XML_vAnchor
), sVAnchor
.getStr() );
9004 void DocxAttributeOutput::FormatHorizOrientation( const SwFormatHoriOrient
& rFlyHori
)
9006 OString sAlign
= convertToOOXMLHoriOrient( rFlyHori
.GetHoriOrient(), rFlyHori
.IsPosToggle() );
9007 OString sHAnchor
= convertToOOXMLHoriOrientRel( rFlyHori
.GetRelationOrient() );
9009 if (m_rExport
.SdrExporter().getTextFrameSyntax())
9011 m_rExport
.SdrExporter().getTextFrameStyle().append(";margin-left:").append(double(rFlyHori
.GetPos()) / 20).append("pt");
9012 if ( !sAlign
.isEmpty() )
9013 m_rExport
.SdrExporter().getTextFrameStyle().append(";mso-position-horizontal:").append(sAlign
);
9014 m_rExport
.SdrExporter().getTextFrameStyle().append(";mso-position-horizontal-relative:").append(sHAnchor
);
9016 else if (m_rExport
.SdrExporter().getDMLTextFrameSyntax())
9019 else if ( m_rExport
.m_bOutFlyFrameAttrs
)
9021 if ( !sAlign
.isEmpty() )
9022 AddToAttrList( m_rExport
.SdrExporter().getFlyAttrList(), FSNS( XML_w
, XML_xAlign
), sAlign
.getStr() );
9024 AddToAttrList( m_rExport
.SdrExporter().getFlyAttrList(), FSNS( XML_w
, XML_x
),
9025 OString::number( rFlyHori
.GetPos() ).getStr() );
9026 AddToAttrList( m_rExport
.SdrExporter().getFlyAttrList(), FSNS( XML_w
, XML_hAnchor
), sHAnchor
.getStr() );
9030 void DocxAttributeOutput::FormatAnchor( const SwFormatAnchor
& )
9032 // Fly frames: anchors here aren't matching the anchors in docx
9035 static std::optional
<sal_Int32
> lcl_getDmlAlpha(const SvxBrushItem
& rBrush
)
9037 std::optional
<sal_Int32
> oRet
;
9038 sal_Int32 nTransparency
= rBrush
.GetColor().GetTransparency();
9041 // Convert transparency to percent
9042 sal_Int8 nTransparencyPercent
= SvxBrushItem::TransparencyToPercent(nTransparency
);
9044 // Calculate alpha value
9045 // Consider oox/source/drawingml/color.cxx : getTransparency() function.
9046 sal_Int32 nAlpha
= ::oox::drawingml::MAX_PERCENT
- ( ::oox::drawingml::PER_PERCENT
* nTransparencyPercent
);
9052 void DocxAttributeOutput::FormatBackground( const SvxBrushItem
& rBrush
)
9054 const Color aColor
= rBrush
.GetColor();
9055 OString sColor
= msfilter::util::ConvertColor( aColor
.GetRGBColor() );
9056 std::optional
<sal_Int32
> oAlpha
= lcl_getDmlAlpha(rBrush
);
9057 if (m_rExport
.SdrExporter().getTextFrameSyntax())
9062 // Calculate opacity value
9063 // Consider oox/source/vml/vmlformatting.cxx : decodeColor() function.
9064 double fOpacity
= static_cast<double>(*oAlpha
) * 65535 / ::oox::drawingml::MAX_PERCENT
;
9065 OUString sOpacity
= OUString::number(fOpacity
) + "f";
9067 AddToAttrList( m_rExport
.SdrExporter().getFlyFillAttrList(), XML_opacity
, OUStringToOString(sOpacity
, RTL_TEXTENCODING_UTF8
).getStr() );
9070 sColor
= "#" + sColor
;
9071 AddToAttrList( m_rExport
.SdrExporter().getFlyAttrList(), XML_fillcolor
, sColor
.getStr() );
9073 else if (m_rExport
.SdrExporter().getDMLTextFrameSyntax())
9075 bool bImageBackground
= false;
9076 const SfxPoolItem
* pItem
= GetExport().HasItem(XATTR_FILLSTYLE
);
9079 const XFillStyleItem
* pFillStyle
= static_cast<const XFillStyleItem
*>(pItem
);
9080 if(pFillStyle
->GetValue() == drawing::FillStyle_BITMAP
)
9082 bImageBackground
= true;
9085 if (!bImageBackground
)
9087 m_pSerializer
->startElementNS(XML_a
, XML_solidFill
);
9088 m_pSerializer
->startElementNS(XML_a
, XML_srgbClr
, XML_val
, sColor
);
9090 m_pSerializer
->singleElementNS(XML_a
, XML_alpha
,
9091 XML_val
, OString::number(*oAlpha
));
9092 m_pSerializer
->endElementNS(XML_a
, XML_srgbClr
);
9093 m_pSerializer
->endElementNS(XML_a
, XML_solidFill
);
9096 else if ( !m_rExport
.m_bOutPageDescs
)
9098 // compare fill color with the original fill color
9099 OString sOriginalFill
= OUStringToOString(
9100 m_sOriginalBackgroundColor
, RTL_TEXTENCODING_UTF8
);
9102 if ( aColor
== COL_AUTO
)
9105 if( !m_pBackgroundAttrList
.is() )
9107 m_pBackgroundAttrList
= FastSerializerHelper::createAttrList();
9108 m_pBackgroundAttrList
->add( FSNS( XML_w
, XML_fill
), sColor
.getStr() );
9109 m_pBackgroundAttrList
->add( FSNS( XML_w
, XML_val
), "clear" );
9111 else if ( sOriginalFill
!= sColor
)
9113 // fill was modified during edition, theme fill attribute must be dropped
9114 m_pBackgroundAttrList
= FastSerializerHelper::createAttrList();
9115 m_pBackgroundAttrList
->add( FSNS( XML_w
, XML_fill
), sColor
.getStr() );
9116 m_pBackgroundAttrList
->add( FSNS( XML_w
, XML_val
), "clear" );
9118 m_sOriginalBackgroundColor
.clear();
9122 void DocxAttributeOutput::FormatFillStyle( const XFillStyleItem
& rFillStyle
)
9124 if (!m_bIgnoreNextFill
)
9125 m_oFillStyle
= rFillStyle
.GetValue();
9127 m_bIgnoreNextFill
= false;
9129 // Don't round-trip grabbag OriginalBackground if the background has been cleared.
9130 if ( m_pBackgroundAttrList
.is() && m_sOriginalBackgroundColor
!= "auto" && rFillStyle
.GetValue() == drawing::FillStyle_NONE
)
9131 m_pBackgroundAttrList
.clear();
9134 void DocxAttributeOutput::FormatFillGradient( const XFillGradientItem
& rFillGradient
)
9136 if (m_oFillStyle
&& *m_oFillStyle
== drawing::FillStyle_GRADIENT
&& !m_rExport
.SdrExporter().getDMLTextFrameSyntax())
9138 AddToAttrList( m_rExport
.SdrExporter().getFlyFillAttrList(), XML_type
, "gradient" );
9140 const XGradient
& rGradient
= rFillGradient
.GetGradientValue();
9141 OString sStartColor
= msfilter::util::ConvertColor(rGradient
.GetStartColor());
9142 OString sEndColor
= msfilter::util::ConvertColor(rGradient
.GetEndColor());
9144 // Calculate the angle that was originally in the imported DOCX file
9145 // (reverse calculate the angle that was converted in the file
9146 // /oox/source/vml/vmlformatting.cxx :: FillModel::pushToPropMap
9148 // /oox/source/drawingml/fillproperties.cxx :: FillProperties::pushToPropMap
9149 sal_Int32 nReverseAngle
= (Degree10(4500) - rGradient
.GetAngle()).get();
9150 nReverseAngle
= nReverseAngle
/ 10;
9151 nReverseAngle
= (270 - nReverseAngle
) % 360;
9152 if (nReverseAngle
!= 0)
9153 AddToAttrList( m_rExport
.SdrExporter().getFlyFillAttrList(),
9154 XML_angle
, OString::number( nReverseAngle
).getStr() );
9156 OString sColor1
= sStartColor
;
9157 OString sColor2
= sEndColor
;
9159 switch (rGradient
.GetGradientStyle())
9161 case css::awt::GradientStyle_AXIAL
:
9162 AddToAttrList( m_rExport
.SdrExporter().getFlyFillAttrList(), XML_focus
, "50%" );
9163 // If it is an 'axial' gradient - swap the colors
9164 // (because in the import process they were imported swapped)
9165 sColor1
= sEndColor
;
9166 sColor2
= sStartColor
;
9168 case css::awt::GradientStyle_LINEAR
: break;
9169 case css::awt::GradientStyle_RADIAL
: break;
9170 case css::awt::GradientStyle_ELLIPTICAL
: break;
9171 case css::awt::GradientStyle_SQUARE
: break;
9172 case css::awt::GradientStyle_RECT
: break;
9177 sColor1
= "#" + sColor1
;
9178 sColor2
= "#" + sColor2
;
9179 AddToAttrList( m_rExport
.SdrExporter().getFlyAttrList(), XML_fillcolor
, sColor1
.getStr() );
9180 AddToAttrList( m_rExport
.SdrExporter().getFlyFillAttrList(), XML_color2
, sColor2
.getStr() );
9182 else if (m_oFillStyle
&& *m_oFillStyle
== drawing::FillStyle_GRADIENT
&& m_rExport
.SdrExporter().getDMLTextFrameSyntax())
9184 SwFrameFormat
& rFormat(
9185 const_cast<SwFrameFormat
&>(m_rExport
.m_pParentFrame
->GetFrameFormat()));
9186 uno::Reference
<beans::XPropertySet
> const xPropertySet(
9187 SwXTextFrame::CreateXTextFrame(*rFormat
.GetDoc(), &rFormat
),
9189 m_rDrawingML
.SetFS(m_pSerializer
);
9190 m_rDrawingML
.WriteGradientFill(xPropertySet
);
9192 m_oFillStyle
.reset();
9195 void DocxAttributeOutput::FormatBox( const SvxBoxItem
& rBox
)
9197 if (m_rExport
.SdrExporter().getDMLTextFrameSyntax())
9199 // ugh, exporting fill here is quite some hack... this OutputItemSet abstraction is quite leaky
9200 // <a:gradFill> should be before <a:ln>.
9201 const SfxPoolItem
* pItem
= GetExport().HasItem(XATTR_FILLSTYLE
);
9204 const XFillStyleItem
* pFillStyle
= static_cast<const XFillStyleItem
*>(pItem
);
9205 FormatFillStyle(*pFillStyle
);
9206 if (m_oFillStyle
&& *m_oFillStyle
== drawing::FillStyle_BITMAP
)
9208 const SdrObject
* pSdrObj
= m_rExport
.m_pParentFrame
->GetFrameFormat().FindRealSdrObject();
9211 uno::Reference
< drawing::XShape
> xShape( const_cast<SdrObject
*>(pSdrObj
)->getUnoShape(), uno::UNO_QUERY
);
9212 uno::Reference
< beans::XPropertySet
> xPropertySet( xShape
, uno::UNO_QUERY
);
9213 m_rDrawingML
.SetFS(m_pSerializer
);
9214 m_rDrawingML
.WriteBlipFill(xPropertySet
, "BackGraphic");
9219 pItem
= GetExport().HasItem(XATTR_FILLGRADIENT
);
9222 const XFillGradientItem
* pFillGradient
= static_cast<const XFillGradientItem
*>(pItem
);
9223 FormatFillGradient(*pFillGradient
);
9225 m_bIgnoreNextFill
= true;
9227 if (m_rExport
.SdrExporter().getTextFrameSyntax() || m_rExport
.SdrExporter().getDMLTextFrameSyntax())
9229 const SvxBorderLine
* pLeft
= rBox
.GetLeft( );
9230 const SvxBorderLine
* pTop
= rBox
.GetTop( );
9231 const SvxBorderLine
* pRight
= rBox
.GetRight( );
9232 const SvxBorderLine
* pBottom
= rBox
.GetBottom( );
9234 if (pLeft
&& pRight
&& pTop
&& pBottom
&&
9235 *pLeft
== *pRight
&& *pLeft
== *pTop
&& *pLeft
== *pBottom
)
9237 // Check border style
9238 SvxBorderLineStyle eBorderStyle
= pTop
->GetBorderLineStyle();
9239 if (eBorderStyle
== SvxBorderLineStyle::NONE
)
9241 if (m_rExport
.SdrExporter().getTextFrameSyntax())
9243 AddToAttrList( m_rExport
.SdrExporter().getFlyAttrList(), 2,
9244 XML_stroked
, "f", XML_strokeweight
, "0pt" );
9249 OString
sColor(msfilter::util::ConvertColor(pTop
->GetColor()));
9250 double const fConverted(editeng::ConvertBorderWidthToWord(pTop
->GetBorderLineStyle(), pTop
->GetWidth()));
9252 if (m_rExport
.SdrExporter().getTextFrameSyntax())
9254 sColor
= "#" + sColor
;
9255 sal_Int32 nWidth
= sal_Int32(fConverted
/ 20);
9256 OString sWidth
= OString::number(nWidth
) + "pt";
9257 AddToAttrList( m_rExport
.SdrExporter().getFlyAttrList(), 2,
9258 XML_strokecolor
, sColor
.getStr(),
9259 XML_strokeweight
, sWidth
.getStr() );
9260 if( SvxBorderLineStyle::DASHED
== pTop
->GetBorderLineStyle() ) // Line Style is Dash type
9261 AddToAttrList( m_rExport
.SdrExporter().getDashLineStyle(),
9262 XML_dashstyle
, "dash" );
9265 m_rExport
.SdrExporter().writeBoxItemLine(rBox
);
9269 if (m_rExport
.SdrExporter().getDMLTextFrameSyntax())
9271 m_rExport
.SdrExporter().getBodyPrAttrList()->add(XML_lIns
, OString::number(TwipsToEMU(rBox
.GetDistance(SvxBoxItemLine::LEFT
))));
9272 m_rExport
.SdrExporter().getBodyPrAttrList()->add(XML_tIns
, OString::number(TwipsToEMU(rBox
.GetDistance(SvxBoxItemLine::TOP
))));
9273 m_rExport
.SdrExporter().getBodyPrAttrList()->add(XML_rIns
, OString::number(TwipsToEMU(rBox
.GetDistance(SvxBoxItemLine::RIGHT
))));
9274 m_rExport
.SdrExporter().getBodyPrAttrList()->add(XML_bIns
, OString::number(TwipsToEMU(rBox
.GetDistance(SvxBoxItemLine::BOTTOM
))));
9278 // v:textbox's inset attribute: inner margin values for textbox text - write only non-default values
9279 double fDistanceLeftTwips
= double(rBox
.GetDistance(SvxBoxItemLine::LEFT
));
9280 double fDistanceTopTwips
= double(rBox
.GetDistance(SvxBoxItemLine::TOP
));
9281 double fDistanceRightTwips
= double(rBox
.GetDistance(SvxBoxItemLine::RIGHT
));
9282 double fDistanceBottomTwips
= double(rBox
.GetDistance(SvxBoxItemLine::BOTTOM
));
9284 // Convert 'TWIPS' to 'INCH' (because in Word the default values are in Inches)
9285 double fDistanceLeftInch
= fDistanceLeftTwips
/ 1440;
9286 double fDistanceTopInch
= fDistanceTopTwips
/ 1440;
9287 double fDistanceRightInch
= fDistanceRightTwips
/ 1440;
9288 double fDistanceBottomInch
= fDistanceBottomTwips
/ 1440;
9290 // This code will write ONLY the non-default values. The values are in 'left','top','right','bottom' order.
9291 // so 'bottom' is checked if it is default and if it is non-default - all the values will be written
9292 // otherwise - 'right' is checked if it is default and if it is non-default - all the values except for 'bottom' will be written
9294 OStringBuffer aInset
;
9295 if(!aInset
.isEmpty() || fDistanceBottomInch
!= 0.05)
9296 aInset
.insert(0, "," + OString::number(fDistanceBottomInch
) + "in");
9298 if(!aInset
.isEmpty() || fDistanceRightInch
!= 0.1)
9299 aInset
.insert(0, "," + OString::number(fDistanceRightInch
) + "in");
9301 if(!aInset
.isEmpty() || fDistanceTopInch
!= 0.05)
9302 aInset
.insert(0, "," + OString::number(fDistanceTopInch
) + "in");
9304 if(!aInset
.isEmpty() || fDistanceLeftInch
!= 0.1)
9305 aInset
.insert(0, OString::number(fDistanceLeftInch
) + "in");
9307 if (!aInset
.isEmpty())
9308 m_rExport
.SdrExporter().getTextboxAttrList()->add(XML_inset
, aInset
.makeStringAndClear());
9313 OutputBorderOptions aOutputBorderOptions
= lcl_getBoxBorderOptions();
9314 // Check if there is a shadow item
9315 const SfxPoolItem
* pItem
= GetExport().HasItem( RES_SHADOW
);
9318 const SvxShadowItem
* pShadowItem
= static_cast<const SvxShadowItem
*>(pItem
);
9319 aOutputBorderOptions
.aShadowLocation
= pShadowItem
->GetLocation();
9322 if ( m_bOpenedSectPr
&& !GetWritingHeaderFooter())
9325 // Not inside a section
9327 // Open the paragraph's borders tag
9328 m_pSerializer
->startElementNS(XML_w
, XML_pBdr
);
9330 std::map
<SvxBoxItemLine
, css::table::BorderLine2
> aStyleBorders
;
9331 const SvxBoxItem
* pInherited
= nullptr;
9332 if ( GetExport().m_pStyAttr
)
9333 pInherited
= GetExport().m_pStyAttr
->GetItem
<SvxBoxItem
>(RES_BOX
);
9334 else if ( GetExport().m_pCurrentStyle
&& GetExport().m_pCurrentStyle
->DerivedFrom() )
9335 pInherited
= GetExport().m_pCurrentStyle
->DerivedFrom()->GetAttrSet().GetItem
<SvxBoxItem
>(RES_BOX
);
9339 aStyleBorders
[ SvxBoxItemLine::TOP
] = SvxBoxItem::SvxLineToLine(pInherited
->GetTop(), /*bConvert=*/false);
9340 aStyleBorders
[ SvxBoxItemLine::BOTTOM
] = SvxBoxItem::SvxLineToLine(pInherited
->GetBottom(), false);
9341 aStyleBorders
[ SvxBoxItemLine::LEFT
] = SvxBoxItem::SvxLineToLine(pInherited
->GetLeft(), false);
9342 aStyleBorders
[ SvxBoxItemLine::RIGHT
] = SvxBoxItem::SvxLineToLine(pInherited
->GetRight(), false);
9345 impl_borders( m_pSerializer
, rBox
, aOutputBorderOptions
, aStyleBorders
);
9347 // Close the paragraph's borders tag
9348 m_pSerializer
->endElementNS( XML_w
, XML_pBdr
);
9351 void DocxAttributeOutput::FormatColumns_Impl( sal_uInt16 nCols
, const SwFormatCol
& rCol
, bool bEven
, SwTwips nPageSize
)
9353 // Get the columns attributes
9354 FastAttributeList
*pColsAttrList
= FastSerializerHelper::createAttrList();
9356 pColsAttrList
->add( FSNS( XML_w
, XML_num
),
9357 OString::number( nCols
). getStr( ) );
9359 const char* pEquals
= "false";
9362 sal_uInt16 nWidth
= rCol
.GetGutterWidth( true );
9363 pColsAttrList
->add( FSNS( XML_w
, XML_space
),
9364 OString::number( nWidth
).getStr( ) );
9369 pColsAttrList
->add( FSNS( XML_w
, XML_equalWidth
), pEquals
);
9371 bool bHasSep
= (COLADJ_NONE
!= rCol
.GetLineAdj());
9373 pColsAttrList
->add( FSNS( XML_w
, XML_sep
), OString::boolean( bHasSep
) );
9375 // Write the element
9376 m_pSerializer
->startElementNS( XML_w
, XML_cols
, pColsAttrList
);
9378 // Write the columns width if non-equals
9379 const SwColumns
& rColumns
= rCol
.GetColumns( );
9382 for ( sal_uInt16 n
= 0; n
< nCols
; ++n
)
9384 FastAttributeList
*pColAttrList
= FastSerializerHelper::createAttrList();
9385 sal_uInt16 nWidth
= rCol
.CalcPrtColWidth( n
, static_cast<sal_uInt16
>(nPageSize
) );
9386 pColAttrList
->add( FSNS( XML_w
, XML_w
),
9387 OString::number( nWidth
).getStr( ) );
9389 if ( n
+ 1 != nCols
)
9391 sal_uInt16 nSpacing
= rColumns
[n
].GetRight( ) + rColumns
[n
+ 1].GetLeft( );
9392 pColAttrList
->add( FSNS( XML_w
, XML_space
),
9393 OString::number( nSpacing
).getStr( ) );
9396 m_pSerializer
->singleElementNS( XML_w
, XML_col
, pColAttrList
);
9400 m_pSerializer
->endElementNS( XML_w
, XML_cols
);
9403 void DocxAttributeOutput::FormatKeep( const SvxFormatKeepItem
& rItem
)
9405 m_pSerializer
->singleElementNS( XML_w
, XML_keepNext
,
9406 FSNS( XML_w
, XML_val
), OString::boolean( rItem
.GetValue() ) );
9409 void DocxAttributeOutput::FormatTextGrid( const SwTextGridItem
& rGrid
)
9411 FastAttributeList
*pGridAttrList
= FastSerializerHelper::createAttrList();
9414 switch ( rGrid
.GetGridType( ) )
9418 sGridType
= OString( "default" );
9420 case GRID_LINES_ONLY
:
9421 sGridType
= OString( "lines" );
9423 case GRID_LINES_CHARS
:
9424 if ( rGrid
.IsSnapToChars( ) )
9425 sGridType
= OString( "snapToChars" );
9427 sGridType
= OString( "linesAndChars" );
9430 pGridAttrList
->add( FSNS( XML_w
, XML_type
), sGridType
.getStr( ) );
9432 sal_uInt16 nHeight
= rGrid
.GetBaseHeight() + rGrid
.GetRubyHeight();
9433 pGridAttrList
->add( FSNS( XML_w
, XML_linePitch
),
9434 OString::number( nHeight
).getStr( ) );
9436 pGridAttrList
->add( FSNS( XML_w
, XML_charSpace
),
9437 OString::number( GridCharacterPitch( rGrid
) ).getStr( ) );
9439 m_pSerializer
->singleElementNS( XML_w
, XML_docGrid
, pGridAttrList
);
9442 void DocxAttributeOutput::FormatLineNumbering( const SwFormatLineNumber
& rNumbering
)
9444 if ( !rNumbering
.IsCount( ) )
9445 m_pSerializer
->singleElementNS(XML_w
, XML_suppressLineNumbers
);
9448 void DocxAttributeOutput::FormatFrameDirection( const SvxFrameDirectionItem
& rDirection
)
9452 SvxFrameDirection nDir
= rDirection
.GetValue();
9454 if ( nDir
== SvxFrameDirection::Environment
)
9455 nDir
= GetExport( ).GetDefaultFrameDirection( );
9460 case SvxFrameDirection::Horizontal_LR_TB
:
9461 sTextFlow
= OString( "lrTb" );
9463 case SvxFrameDirection::Horizontal_RL_TB
:
9464 sTextFlow
= OString( "lrTb" );
9467 case SvxFrameDirection::Vertical_LR_TB
: // many things but not this one
9468 case SvxFrameDirection::Vertical_RL_TB
:
9469 sTextFlow
= OString( "tbRl" );
9473 if ( m_rExport
.m_bOutPageDescs
)
9475 m_pSerializer
->singleElementNS(XML_w
, XML_textDirection
, FSNS(XML_w
, XML_val
), sTextFlow
);
9477 m_pSerializer
->singleElementNS(XML_w
, XML_bidi
);
9479 else if ( !m_rExport
.m_bOutFlyFrameAttrs
)
9482 m_pSerializer
->singleElementNS(XML_w
, XML_bidi
, FSNS(XML_w
, XML_val
), "1");
9484 m_pSerializer
->singleElementNS(XML_w
, XML_bidi
, FSNS(XML_w
, XML_val
), "0");
9488 void DocxAttributeOutput::ParaGrabBag(const SfxGrabBagItem
& rItem
)
9490 const std::map
<OUString
, css::uno::Any
>& rMap
= rItem
.GetGrabBag();
9491 for ( const auto & rGrabBagElement
: rMap
)
9493 if (rGrabBagElement
.first
== "MirrorIndents")
9494 m_pSerializer
->singleElementNS(XML_w
, XML_mirrorIndents
);
9495 else if (rGrabBagElement
.first
== "ParaTopMarginBeforeAutoSpacing")
9497 m_bParaBeforeAutoSpacing
= true;
9498 // get fixed value which was set during import
9499 rGrabBagElement
.second
>>= m_nParaBeforeSpacing
;
9500 m_nParaBeforeSpacing
= convertMm100ToTwip(m_nParaBeforeSpacing
);
9501 SAL_INFO("sw.ww8", "DocxAttributeOutput::ParaGrabBag: property =" << rGrabBagElement
.first
<< " : m_nParaBeforeSpacing= " << m_nParaBeforeSpacing
);
9503 else if (rGrabBagElement
.first
== "ParaBottomMarginAfterAutoSpacing")
9505 m_bParaAfterAutoSpacing
= true;
9506 // get fixed value which was set during import
9507 rGrabBagElement
.second
>>= m_nParaAfterSpacing
;
9508 m_nParaAfterSpacing
= convertMm100ToTwip(m_nParaAfterSpacing
);
9509 SAL_INFO("sw.ww8", "DocxAttributeOutput::ParaGrabBag: property =" << rGrabBagElement
.first
<< " : m_nParaBeforeSpacing= " << m_nParaAfterSpacing
);
9511 else if (rGrabBagElement
.first
== "CharThemeFill")
9513 uno::Sequence
<beans::PropertyValue
> aGrabBagSeq
;
9514 rGrabBagElement
.second
>>= aGrabBagSeq
;
9516 for (const auto& rProp
: std::as_const(aGrabBagSeq
))
9518 OString sVal
= OUStringToOString(rProp
.Value
.get
<OUString
>(), RTL_TEXTENCODING_UTF8
);
9523 if (rProp
.Name
== "val")
9524 AddToAttrList(m_pBackgroundAttrList
, FSNS(XML_w
, XML_val
), sVal
.getStr());
9525 else if (rProp
.Name
== "color")
9526 AddToAttrList(m_pBackgroundAttrList
, FSNS(XML_w
, XML_color
), sVal
.getStr());
9527 else if (rProp
.Name
== "themeColor")
9528 AddToAttrList(m_pBackgroundAttrList
, FSNS(XML_w
, XML_themeColor
), sVal
.getStr());
9529 else if (rProp
.Name
== "themeTint")
9530 AddToAttrList(m_pBackgroundAttrList
, FSNS(XML_w
, XML_themeTint
), sVal
.getStr());
9531 else if (rProp
.Name
== "themeShade")
9532 AddToAttrList(m_pBackgroundAttrList
, FSNS(XML_w
, XML_themeShade
), sVal
.getStr());
9533 else if (rProp
.Name
== "fill")
9534 AddToAttrList(m_pBackgroundAttrList
, FSNS(XML_w
, XML_fill
), sVal
.getStr());
9535 else if (rProp
.Name
== "themeFill")
9536 AddToAttrList(m_pBackgroundAttrList
, FSNS(XML_w
, XML_themeFill
), sVal
.getStr());
9537 else if (rProp
.Name
== "themeFillTint")
9538 AddToAttrList(m_pBackgroundAttrList
, FSNS(XML_w
, XML_themeFillTint
), sVal
.getStr());
9539 else if (rProp
.Name
== "themeFillShade")
9540 AddToAttrList(m_pBackgroundAttrList
, FSNS(XML_w
, XML_themeFillShade
), sVal
.getStr());
9541 else if (rProp
.Name
== "originalColor")
9542 rProp
.Value
>>= m_sOriginalBackgroundColor
;
9545 else if (rGrabBagElement
.first
== "SdtPr")
9547 const uno::Sequence
<beans::PropertyValue
> aGrabBagSdt
=
9548 rGrabBagElement
.second
.get
< uno::Sequence
<beans::PropertyValue
> >();
9549 for (const beans::PropertyValue
& aPropertyValue
: aGrabBagSdt
)
9551 if (aPropertyValue
.Name
== "ooxml:CT_SdtPr_docPartObj" ||
9552 aPropertyValue
.Name
== "ooxml:CT_SdtPr_docPartList")
9554 if (aPropertyValue
.Name
== "ooxml:CT_SdtPr_docPartObj")
9555 m_nParagraphSdtPrToken
= FSNS( XML_w
, XML_docPartObj
);
9556 else if (aPropertyValue
.Name
== "ooxml:CT_SdtPr_docPartList")
9557 m_nParagraphSdtPrToken
= FSNS( XML_w
, XML_docPartList
);
9559 uno::Sequence
<beans::PropertyValue
> aGrabBag
;
9560 aPropertyValue
.Value
>>= aGrabBag
;
9561 for (const auto& rProp
: std::as_const(aGrabBag
))
9563 OUString sValue
= rProp
.Value
.get
<OUString
>();
9564 if (rProp
.Name
== "ooxml:CT_SdtDocPart_docPartGallery")
9565 AddToAttrList( m_pParagraphSdtPrTokenChildren
,
9566 FSNS( XML_w
, XML_docPartGallery
),
9567 OUStringToOString( sValue
, RTL_TEXTENCODING_UTF8
).getStr() );
9568 else if (rProp
.Name
== "ooxml:CT_SdtDocPart_docPartCategory")
9569 AddToAttrList( m_pParagraphSdtPrTokenChildren
,
9570 FSNS( XML_w
, XML_docPartCategory
),
9571 OUStringToOString( sValue
, RTL_TEXTENCODING_UTF8
).getStr() );
9572 else if (rProp
.Name
== "ooxml:CT_SdtDocPart_docPartUnique")
9574 if (sValue
.isEmpty())
9576 AddToAttrList( m_pParagraphSdtPrTokenChildren
, FSNS( XML_w
, XML_docPartUnique
),
9577 OUStringToOString( sValue
, RTL_TEXTENCODING_UTF8
).getStr() );
9581 else if (aPropertyValue
.Name
== "ooxml:CT_SdtPr_equation")
9582 m_nParagraphSdtPrToken
= FSNS( XML_w
, XML_equation
);
9583 else if (aPropertyValue
.Name
== "ooxml:CT_SdtPr_picture")
9584 m_nParagraphSdtPrToken
= FSNS( XML_w
, XML_picture
);
9585 else if (aPropertyValue
.Name
== "ooxml:CT_SdtPr_citation")
9586 m_nParagraphSdtPrToken
= FSNS( XML_w
, XML_citation
);
9587 else if (aPropertyValue
.Name
== "ooxml:CT_SdtPr_group")
9588 m_nParagraphSdtPrToken
= FSNS( XML_w
, XML_group
);
9589 else if (aPropertyValue
.Name
== "ooxml:CT_SdtPr_text")
9590 m_nParagraphSdtPrToken
= FSNS(XML_w
, XML_text
);
9591 else if (aPropertyValue
.Name
== "ooxml:CT_SdtPr_dataBinding" && !m_pParagraphSdtPrDataBindingAttrs
.is())
9593 uno::Sequence
<beans::PropertyValue
> aGrabBag
;
9594 aPropertyValue
.Value
>>= aGrabBag
;
9595 for (const auto& rProp
: std::as_const(aGrabBag
))
9597 OUString sValue
= rProp
.Value
.get
<OUString
>();
9598 if (rProp
.Name
== "ooxml:CT_DataBinding_prefixMappings")
9599 AddToAttrList( m_pParagraphSdtPrDataBindingAttrs
,
9600 FSNS( XML_w
, XML_prefixMappings
),
9601 OUStringToOString( sValue
, RTL_TEXTENCODING_UTF8
).getStr() );
9602 else if (rProp
.Name
== "ooxml:CT_DataBinding_xpath")
9603 AddToAttrList( m_pParagraphSdtPrDataBindingAttrs
,
9604 FSNS( XML_w
, XML_xpath
),
9605 OUStringToOString( sValue
, RTL_TEXTENCODING_UTF8
).getStr() );
9606 else if (rProp
.Name
== "ooxml:CT_DataBinding_storeItemID")
9607 AddToAttrList( m_pParagraphSdtPrDataBindingAttrs
,
9608 FSNS( XML_w
, XML_storeItemID
),
9609 OUStringToOString( sValue
, RTL_TEXTENCODING_UTF8
).getStr() );
9612 else if (aPropertyValue
.Name
== "ooxml:CT_SdtPr_alias" && m_aParagraphSdtPrAlias
.isEmpty())
9614 if (!(aPropertyValue
.Value
>>= m_aParagraphSdtPrAlias
))
9615 SAL_WARN("sw.ww8", "DocxAttributeOutput::ParaGrabBag: unexpected sdt alias value");
9616 m_aStartedParagraphSdtPrAlias
= m_aParagraphSdtPrAlias
;
9618 else if (aPropertyValue
.Name
== "ooxml:CT_SdtPr_checkbox")
9620 m_nParagraphSdtPrToken
= FSNS( XML_w14
, XML_checkbox
);
9621 uno::Sequence
<beans::PropertyValue
> aGrabBag
;
9622 aPropertyValue
.Value
>>= aGrabBag
;
9623 for (const auto& rProp
: std::as_const(aGrabBag
))
9625 OUString sValue
= rProp
.Value
.get
<OUString
>();
9626 if (rProp
.Name
== "ooxml:CT_SdtCheckbox_checked")
9627 AddToAttrList( m_pParagraphSdtPrTokenChildren
,
9628 FSNS( XML_w14
, XML_checked
),
9629 OUStringToOString( sValue
, RTL_TEXTENCODING_UTF8
).getStr() );
9630 else if (rProp
.Name
== "ooxml:CT_SdtCheckbox_checkedState")
9631 AddToAttrList( m_pParagraphSdtPrTokenChildren
,
9632 FSNS( XML_w14
, XML_checkedState
),
9633 OUStringToOString( sValue
, RTL_TEXTENCODING_UTF8
).getStr() );
9634 else if (rProp
.Name
== "ooxml:CT_SdtCheckbox_uncheckedState")
9635 AddToAttrList( m_pParagraphSdtPrTokenChildren
,
9636 FSNS( XML_w14
, XML_uncheckedState
),
9637 OUStringToOString( sValue
, RTL_TEXTENCODING_UTF8
).getStr() );
9640 else if (aPropertyValue
.Name
== "ooxml:CT_SdtPr_id")
9641 m_bParagraphSdtHasId
= true;
9643 SAL_WARN("sw.ww8", "DocxAttributeOutput::ParaGrabBag: unhandled SdtPr grab bag property " << aPropertyValue
.Name
);
9646 else if (rGrabBagElement
.first
== "ParaCnfStyle")
9648 uno::Sequence
<beans::PropertyValue
> aAttributes
= rGrabBagElement
.second
.get
< uno::Sequence
<beans::PropertyValue
> >();
9649 m_pTableStyleExport
->CnfStyle(aAttributes
);
9651 else if (rGrabBagElement
.first
== "ParaSdtEndBefore")
9653 // Handled already in StartParagraph().
9656 SAL_WARN("sw.ww8", "DocxAttributeOutput::ParaGrabBag: unhandled grab bag property " << rGrabBagElement
.first
);
9660 void DocxAttributeOutput::CharGrabBag( const SfxGrabBagItem
& rItem
)
9662 if (m_bPreventDoubleFieldsHandling
)
9665 const std::map
< OUString
, css::uno::Any
>& rMap
= rItem
.GetGrabBag();
9667 // get original values of theme-derived properties to check if they have changed during the edition
9668 bool bWriteCSTheme
= true;
9669 bool bWriteAsciiTheme
= true;
9670 bool bWriteEastAsiaTheme
= true;
9671 bool bWriteThemeFontColor
= true;
9672 OUString sOriginalValue
;
9673 for ( const auto & rGrabBagElement
: rMap
)
9675 if ( m_pFontsAttrList
.is() && rGrabBagElement
.first
== "CharThemeFontNameCs" )
9677 if ( rGrabBagElement
.second
>>= sOriginalValue
)
9679 ( m_pFontsAttrList
->getOptionalValue( FSNS( XML_w
, XML_cs
) ) == sOriginalValue
);
9681 else if ( m_pFontsAttrList
.is() && rGrabBagElement
.first
== "CharThemeFontNameAscii" )
9683 if ( rGrabBagElement
.second
>>= sOriginalValue
)
9685 ( m_pFontsAttrList
->getOptionalValue( FSNS( XML_w
, XML_ascii
) ) == sOriginalValue
);
9687 else if ( m_pFontsAttrList
.is() && rGrabBagElement
.first
== "CharThemeFontNameEastAsia" )
9689 if ( rGrabBagElement
.second
>>= sOriginalValue
)
9690 bWriteEastAsiaTheme
=
9691 ( m_pFontsAttrList
->getOptionalValue( FSNS( XML_w
, XML_eastAsia
) ) == sOriginalValue
);
9693 else if ( m_pColorAttrList
.is() && rGrabBagElement
.first
== "CharThemeOriginalColor" )
9695 if ( rGrabBagElement
.second
>>= sOriginalValue
)
9696 bWriteThemeFontColor
=
9697 ( m_pColorAttrList
->getOptionalValue( FSNS( XML_w
, XML_val
) ) == sOriginalValue
);
9701 // save theme attributes back to the run properties
9703 for ( const auto & rGrabBagElement
: rMap
)
9705 if ( rGrabBagElement
.first
== "CharThemeNameAscii" && bWriteAsciiTheme
)
9707 rGrabBagElement
.second
>>= str
;
9708 AddToAttrList( m_pFontsAttrList
, FSNS( XML_w
, XML_asciiTheme
),
9709 OUStringToOString( str
, RTL_TEXTENCODING_UTF8
).getStr() );
9711 else if ( rGrabBagElement
.first
== "CharThemeNameCs" && bWriteCSTheme
)
9713 rGrabBagElement
.second
>>= str
;
9714 AddToAttrList( m_pFontsAttrList
, FSNS( XML_w
, XML_cstheme
),
9715 OUStringToOString( str
, RTL_TEXTENCODING_UTF8
).getStr() );
9717 else if ( rGrabBagElement
.first
== "CharThemeNameEastAsia" && bWriteEastAsiaTheme
)
9719 rGrabBagElement
.second
>>= str
;
9720 AddToAttrList( m_pFontsAttrList
, FSNS( XML_w
, XML_eastAsiaTheme
),
9721 OUStringToOString( str
, RTL_TEXTENCODING_UTF8
).getStr() );
9723 else if ( rGrabBagElement
.first
== "CharThemeNameHAnsi" && bWriteAsciiTheme
)
9724 // this is not a mistake: in LibO we don't directly support the hAnsi family
9725 // of attributes so we save the same value from ascii attributes instead
9727 rGrabBagElement
.second
>>= str
;
9728 AddToAttrList( m_pFontsAttrList
, FSNS( XML_w
, XML_hAnsiTheme
),
9729 OUStringToOString( str
, RTL_TEXTENCODING_UTF8
).getStr() );
9731 else if ( rGrabBagElement
.first
== "CharThemeColor" && bWriteThemeFontColor
)
9733 rGrabBagElement
.second
>>= str
;
9734 AddToAttrList( m_pColorAttrList
, FSNS( XML_w
, XML_themeColor
),
9735 OUStringToOString( str
, RTL_TEXTENCODING_UTF8
).getStr() );
9737 else if ( rGrabBagElement
.first
== "CharThemeColorShade" )
9739 rGrabBagElement
.second
>>= str
;
9740 AddToAttrList( m_pColorAttrList
, FSNS( XML_w
, XML_themeShade
),
9741 OUStringToOString( str
, RTL_TEXTENCODING_UTF8
).getStr() );
9743 else if ( rGrabBagElement
.first
== "CharThemeColorTint" )
9745 rGrabBagElement
.second
>>= str
;
9746 AddToAttrList( m_pColorAttrList
, FSNS( XML_w
, XML_themeTint
),
9747 OUStringToOString( str
, RTL_TEXTENCODING_UTF8
).getStr() );
9749 else if( rGrabBagElement
.first
== "CharThemeFontNameCs" ||
9750 rGrabBagElement
.first
== "CharThemeFontNameAscii" ||
9751 rGrabBagElement
.first
== "CharThemeFontNameEastAsia" ||
9752 rGrabBagElement
.first
== "CharThemeOriginalColor" )
9754 // just skip these, they were processed before
9756 else if(rGrabBagElement
.first
== "CharGlowTextEffect" ||
9757 rGrabBagElement
.first
== "CharShadowTextEffect" ||
9758 rGrabBagElement
.first
== "CharReflectionTextEffect" ||
9759 rGrabBagElement
.first
== "CharTextOutlineTextEffect" ||
9760 rGrabBagElement
.first
== "CharTextFillTextEffect" ||
9761 rGrabBagElement
.first
== "CharScene3DTextEffect" ||
9762 rGrabBagElement
.first
== "CharProps3DTextEffect" ||
9763 rGrabBagElement
.first
== "CharLigaturesTextEffect" ||
9764 rGrabBagElement
.first
== "CharNumFormTextEffect" ||
9765 rGrabBagElement
.first
== "CharNumSpacingTextEffect" ||
9766 rGrabBagElement
.first
== "CharStylisticSetsTextEffect" ||
9767 rGrabBagElement
.first
== "CharCntxtAltsTextEffect")
9769 beans::PropertyValue aPropertyValue
;
9770 rGrabBagElement
.second
>>= aPropertyValue
;
9771 m_aTextEffectsGrabBag
.push_back(aPropertyValue
);
9773 else if (rGrabBagElement
.first
== "SdtEndBefore")
9775 if (m_bStartedCharSdt
)
9776 m_bEndCharSdt
= true;
9778 else if (rGrabBagElement
.first
== "SdtPr" && FLY_NOT_PROCESSED
!= m_nStateOfFlyFrame
)
9780 const uno::Sequence
<beans::PropertyValue
> aGrabBagSdt
=
9781 rGrabBagElement
.second
.get
< uno::Sequence
<beans::PropertyValue
> >();
9782 for (const beans::PropertyValue
& aPropertyValue
: aGrabBagSdt
)
9784 if (aPropertyValue
.Name
== "ooxml:CT_SdtPr_checkbox")
9786 m_nRunSdtPrToken
= FSNS( XML_w14
, XML_checkbox
);
9787 uno::Sequence
<beans::PropertyValue
> aGrabBag
;
9788 aPropertyValue
.Value
>>= aGrabBag
;
9789 for (const auto& rProp
: std::as_const(aGrabBag
))
9791 OUString sValue
= rProp
.Value
.get
<OUString
>();
9792 if (rProp
.Name
== "ooxml:CT_SdtCheckbox_checked")
9793 AddToAttrList( m_pRunSdtPrTokenChildren
,
9794 FSNS( XML_w14
, XML_checked
),
9795 OUStringToOString( sValue
, RTL_TEXTENCODING_UTF8
).getStr() );
9796 else if (rProp
.Name
== "ooxml:CT_SdtCheckbox_checkedState")
9797 AddToAttrList( m_pRunSdtPrTokenChildren
,
9798 FSNS( XML_w14
, XML_checkedState
),
9799 OUStringToOString( sValue
, RTL_TEXTENCODING_UTF8
).getStr() );
9800 else if (rProp
.Name
== "ooxml:CT_SdtCheckbox_uncheckedState")
9801 AddToAttrList( m_pRunSdtPrTokenChildren
,
9802 FSNS( XML_w14
, XML_uncheckedState
),
9803 OUStringToOString( sValue
, RTL_TEXTENCODING_UTF8
).getStr() );
9806 else if (aPropertyValue
.Name
== "ooxml:CT_SdtPr_dataBinding" && !m_pRunSdtPrDataBindingAttrs
.is())
9808 uno::Sequence
<beans::PropertyValue
> aGrabBag
;
9809 aPropertyValue
.Value
>>= aGrabBag
;
9810 for (const auto& rProp
: std::as_const(aGrabBag
))
9812 OUString sValue
= rProp
.Value
.get
<OUString
>();
9813 if (rProp
.Name
== "ooxml:CT_DataBinding_prefixMappings")
9814 AddToAttrList( m_pRunSdtPrDataBindingAttrs
,
9815 FSNS( XML_w
, XML_prefixMappings
),
9816 OUStringToOString( sValue
, RTL_TEXTENCODING_UTF8
).getStr() );
9817 else if (rProp
.Name
== "ooxml:CT_DataBinding_xpath")
9818 AddToAttrList( m_pRunSdtPrDataBindingAttrs
,
9819 FSNS( XML_w
, XML_xpath
),
9820 OUStringToOString( sValue
, RTL_TEXTENCODING_UTF8
).getStr() );
9821 else if (rProp
.Name
== "ooxml:CT_DataBinding_storeItemID")
9822 AddToAttrList( m_pRunSdtPrDataBindingAttrs
,
9823 FSNS( XML_w
, XML_storeItemID
),
9824 OUStringToOString( sValue
, RTL_TEXTENCODING_UTF8
).getStr() );
9827 else if (aPropertyValue
.Name
== "ooxml:CT_SdtPr_alias" && m_aRunSdtPrAlias
.isEmpty())
9829 if (!(aPropertyValue
.Value
>>= m_aRunSdtPrAlias
))
9830 SAL_WARN("sw.ww8", "DocxAttributeOutput::CharGrabBag: unexpected sdt alias value");
9832 //do not overwrite the parent node.
9833 else if (aPropertyValue
.Name
== "ooxml:CT_SdtPr_text" && !m_pRunSdtPrTokenChildren
.is())
9834 m_nRunSdtPrToken
= FSNS( XML_w
, XML_text
);
9835 else if (aPropertyValue
.Name
== "ooxml:CT_SdtPr_id" && m_nRunSdtPrToken
== 0)
9836 // only write id token as a marker if no other exist
9837 m_nRunSdtPrToken
= FSNS( XML_w
, XML_id
);
9838 else if (aPropertyValue
.Name
== "ooxml:CT_SdtPr_citation")
9839 m_nRunSdtPrToken
= FSNS( XML_w
, XML_citation
);
9843 SAL_INFO("sw.ww8", "DocxAttributeOutput::CharGrabBag: unhandled grab bag property " << rGrabBagElement
.first
);
9847 DocxAttributeOutput::DocxAttributeOutput( DocxExport
&rExport
, const FSHelperPtr
& pSerializer
, oox::drawingml::DrawingML
* pDrawingML
)
9848 : AttributeOutputBase(rExport
.GetFilter().getFileUrl()),
9849 m_rExport( rExport
),
9850 m_pSerializer( pSerializer
),
9851 m_rDrawingML( *pDrawingML
),
9852 m_bEndCharSdt(false),
9853 m_bStartedCharSdt(false),
9854 m_bStartedParaSdt(false),
9855 m_endPageRef( false ),
9856 m_pFootnotesList( new ::docx::FootnotesList() ),
9857 m_pEndnotesList( new ::docx::FootnotesList() ),
9858 m_footnoteEndnoteRefTag( 0 ),
9859 m_footnoteCustomLabel(),
9860 m_pRedlineData( nullptr ),
9862 m_bOpenedSectPr( false ),
9863 m_bHadSectPr(false),
9864 m_bRunTextIsOn( false ),
9865 m_bWritingHeaderFooter( false ),
9866 m_bAnchorLinkedToNode(false),
9867 m_bWritingField( false ),
9868 m_bPreventDoubleFieldsHandling( false ),
9870 m_nNextBookmarkId( 0 ),
9871 m_nNextAnnotationMarkId( 0 ),
9872 m_pCurrentFrame( nullptr ),
9873 m_bParagraphOpened( false ),
9874 m_bParagraphFrameOpen( false ),
9875 m_bIsFirstParagraph( true ),
9876 m_bAlternateContentChoiceOpen( false ),
9877 m_bPostponedProcessingFly( false ),
9878 m_nColBreakStatus( COLBRK_NONE
),
9879 m_bPostponedPageBreak( false ),
9880 m_nTextFrameLevel( 0 ),
9881 m_closeHyperlinkInThisRun( false ),
9882 m_closeHyperlinkInPreviousRun( false ),
9883 m_startedHyperlink( false ),
9884 m_nHyperLinkCount(0),
9885 m_nFieldsInHyperlink( 0 ),
9886 m_bExportingOutline(false),
9888 pendingPlaceholder( nullptr ),
9889 m_postitFieldsMaxId( 0 ),
9892 m_tableReference(new TableReference()),
9893 m_bIgnoreNextFill(false),
9894 m_pTableStyleExport(std::make_shared
<DocxTableStyleExport
>(rExport
.m_rDoc
, pSerializer
)),
9895 m_bParaBeforeAutoSpacing(false),
9896 m_bParaAfterAutoSpacing(false),
9897 m_nParaBeforeSpacing(0),
9898 m_nParaAfterSpacing(0)
9899 , m_nParagraphSdtPrToken(0)
9900 , m_nRunSdtPrToken(0)
9901 , m_nStateOfFlyFrame( FLY_NOT_PROCESSED
)
9902 , m_bParagraphSdtHasId(false)
9904 // Push initial items to the RelId cache. In case the document contains no
9905 // special streams (headers, footers, etc.) then these items are used
9906 // during the full export.
9910 DocxAttributeOutput::~DocxAttributeOutput()
9914 DocxExport
& DocxAttributeOutput::GetExport()
9919 void DocxAttributeOutput::SetSerializer( ::sax_fastparser::FSHelperPtr
const & pSerializer
)
9921 m_pSerializer
= pSerializer
;
9922 m_pTableStyleExport
->SetSerializer(pSerializer
);
9925 bool DocxAttributeOutput::HasFootnotes() const
9927 return !m_pFootnotesList
->isEmpty();
9930 bool DocxAttributeOutput::HasEndnotes() const
9932 return !m_pEndnotesList
->isEmpty();
9935 bool DocxAttributeOutput::HasPostitFields() const
9937 return !m_postitFields
.empty();
9940 void DocxAttributeOutput::BulletDefinition(int nId
, const Graphic
& rGraphic
, Size aSize
)
9942 m_pSerializer
->startElementNS(XML_w
, XML_numPicBullet
,
9943 FSNS(XML_w
, XML_numPicBulletId
), OString::number(nId
));
9945 OStringBuffer aStyle
;
9946 // Size is in twips, we need it in points.
9947 aStyle
.append("width:").append(double(aSize
.Width()) / 20);
9948 aStyle
.append("pt;height:").append(double(aSize
.Height()) / 20).append("pt");
9949 m_pSerializer
->startElementNS(XML_w
, XML_pict
);
9950 m_pSerializer
->startElementNS( XML_v
, XML_shape
,
9951 XML_style
, aStyle
.getStr(),
9952 FSNS(XML_o
, XML_bullet
), "t");
9954 OUString aRelId
= m_rDrawingML
.WriteImage(rGraphic
);
9955 m_pSerializer
->singleElementNS( XML_v
, XML_imagedata
,
9956 FSNS(XML_r
, XML_id
), OUStringToOString(aRelId
, RTL_TEXTENCODING_UTF8
),
9957 FSNS(XML_o
, XML_title
), "");
9959 m_pSerializer
->endElementNS(XML_v
, XML_shape
);
9960 m_pSerializer
->endElementNS(XML_w
, XML_pict
);
9962 m_pSerializer
->endElementNS(XML_w
, XML_numPicBullet
);
9965 void DocxAttributeOutput::AddToAttrList( rtl::Reference
<sax_fastparser::FastAttributeList
>& pAttrList
, sal_Int32 nAttrName
, const char* sAttrValue
)
9967 AddToAttrList( pAttrList
, 1, nAttrName
, sAttrValue
);
9970 void DocxAttributeOutput::AddToAttrList( rtl::Reference
<sax_fastparser::FastAttributeList
>& pAttrList
, sal_Int32 nAttrs
, ... )
9972 if( !pAttrList
.is() )
9973 pAttrList
= FastSerializerHelper::createAttrList();
9976 va_start( args
, nAttrs
);
9977 for( sal_Int32 i
= 0; i
<nAttrs
; i
++)
9979 sal_Int32 nName
= va_arg( args
, sal_Int32
);
9980 const char* pValue
= va_arg( args
, const char* );
9982 pAttrList
->add( nName
, pValue
);
9987 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */