LibreOffice Module sw (master)  1
ww8atr.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 /*
21  * This file contains methods for the WW8 output
22  * (nodes, attributes, formats and chars).
23  */
24 
25 
26 #include <algorithm>
27 #include <hintids.hxx>
28 
29 #include <o3tl/safeint.hxx>
30 #include <vcl/svapp.hxx>
31 #include <vcl/settings.hxx>
32 #include <sal/log.hxx>
33 
34 #include <svl/zformat.hxx>
35 #include <svl/itemiter.hxx>
36 #include <svl/whiter.hxx>
37 #include <svl/grabbagitem.hxx>
38 #include <editeng/fontitem.hxx>
39 #include <editeng/tstpitem.hxx>
40 #include <editeng/adjustitem.hxx>
41 #include <editeng/spltitem.hxx>
42 #include <editeng/widwitem.hxx>
43 #include <editeng/lspcitem.hxx>
44 #include <editeng/keepitem.hxx>
45 #include <editeng/shaditem.hxx>
46 #include <editeng/brushitem.hxx>
47 #include <editeng/postitem.hxx>
48 #include <editeng/wghtitem.hxx>
49 #include <editeng/kernitem.hxx>
51 #include <editeng/cmapitem.hxx>
52 #include <editeng/wrlmitem.hxx>
53 #include <editeng/udlnitem.hxx>
54 #include <editeng/langitem.hxx>
56 #include <editeng/fhgtitem.hxx>
57 #include <editeng/colritem.hxx>
60 #include <editeng/lrspitem.hxx>
61 #include <editeng/ulspitem.hxx>
62 #include <editeng/boxitem.hxx>
63 #include <editeng/contouritem.hxx>
64 #include <editeng/shdditem.hxx>
65 #include <editeng/autokernitem.hxx>
66 #include <editeng/pbinitem.hxx>
68 #include <editeng/twolinesitem.hxx>
73 #include <editeng/pgrditem.hxx>
74 #include <editeng/frmdiritem.hxx>
75 #include <editeng/blinkitem.hxx>
77 #include <editeng/paperinf.hxx>
78 #include <svx/xfillit0.hxx>
79 #include <svx/xflgrit.hxx>
80 #include <fmtfld.hxx>
81 #include <fchrfmt.hxx>
82 #include <fmtfsize.hxx>
83 #include <fmtpdsc.hxx>
84 #include <fmtornt.hxx>
85 #include <fmtanchr.hxx>
86 #include <fmtclds.hxx>
87 #include <fmtsrnd.hxx>
88 #include <fmtftn.hxx>
89 #include <fmtflcnt.hxx>
90 #include <frmatr.hxx>
91 #include <swtable.hxx>
92 #include <fmtinfmt.hxx>
93 #include <txtfld.hxx>
94 #include <txtftn.hxx>
95 #include <poolfmt.hxx>
96 #include <doc.hxx>
100 #include <IDocumentListsAccess.hxx>
101 #include <list.hxx>
102 #include <docary.hxx>
103 #include <pam.hxx>
104 #include <paratr.hxx>
105 #include <fldbas.hxx>
106 #include <docufld.hxx>
107 #include <expfld.hxx>
108 #include <pagedesc.hxx>
109 #include <ndtxt.hxx>
110 #include <swrect.hxx>
111 #include <redline.hxx>
112 #include <reffld.hxx>
113 #include <ftninfo.hxx>
114 #include <charfmt.hxx>
115 #include <section.hxx>
116 #include <fmtline.hxx>
117 #include <tox.hxx>
118 #include <fmtftntx.hxx>
119 #include <breakit.hxx>
120 #include <com/sun/star/i18n/ScriptType.hpp>
121 #include <com/sun/star/i18n/XBreakIterator.hpp>
124 #include <tgrditem.hxx>
125 #include <flddropdown.hxx>
126 #include <chpfld.hxx>
127 #include <fmthdft.hxx>
128 #include <authfld.hxx>
129 #include <dbfld.hxx>
130 
131 #include "sprmids.hxx"
132 
133 #include <fmtcntnt.hxx>
134 #include "writerhelper.hxx"
135 #include "writerwordglue.hxx"
136 #include "wrtww8.hxx"
137 #include "ww8par.hxx"
138 #include "ww8attributeoutput.hxx"
139 #include "fields.hxx"
141 #include <unotools/fltrcfg.hxx>
142 
143 
144 using ::editeng::SvxBorderLine;
145 using namespace ::com::sun::star;
146 using namespace nsSwDocInfoSubType;
147 using namespace sw::util;
148 using namespace sw::types;
149 
150 bool WW8Export::CollapseScriptsforWordOk( sal_uInt16 nScript, sal_uInt16 nWhich )
151 {
152  bool bRet = true;
153  if ( nScript == i18n::ScriptType::ASIAN )
154  {
155  //for asian in ww8, there is only one fontsize
156  //and one fontstyle (posture/weight) for ww6
157  //there is the additional problem that there
158  //is only one font setting for all three scripts
159  switch ( nWhich )
160  {
161  case RES_CHRATR_FONTSIZE:
162  case RES_CHRATR_POSTURE:
163  case RES_CHRATR_WEIGHT:
164  bRet = false;
165  break;
166  case RES_CHRATR_LANGUAGE:
167  case RES_CHRATR_CTL_FONT:
172  default:
173  break;
174  }
175  }
176  else if ( nScript == i18n::ScriptType::COMPLEX )
177  {
178  //Complex is ok in ww8, but for ww6 there is only
179  //one font, one fontsize, one fontsize (weight/posture)
180  //and only one language
181  }
182  else
183  {
184  //for western in ww8, there is only one fontsize
185  //and one fontstyle (posture/weight) for ww6
186  //there is the additional problem that there
187  //is only one font setting for all three scripts
188  switch ( nWhich )
189  {
193  bRet = false;
194  break;
196  case RES_CHRATR_CTL_FONT:
201  default:
202  break;
203  }
204  }
205  return bRet;
206 }
207 
208 
209 void MSWordExportBase::ExportPoolItemsToCHP( ww8::PoolItems &rItems, sal_uInt16 nScript, const SvxFontItem *pFont, bool bWriteCombChars )
210 {
211  for ( const auto& rItem : rItems )
212  {
213  const SfxPoolItem *pItem = rItem.second;
214  sal_uInt16 nWhich = pItem->Which();
215  if ( ( isCHRATR( nWhich ) || isTXTATR( nWhich ) ) && CollapseScriptsforWordOk( nScript, nWhich ) )
216  {
217  //In the id definition, RES_TXTATR_INETFMT must precede RES_TXTATR_CHARFMT, so that link style can overwrite char style.
218  //and in #i24291# it describes "All we want to do is ensure for now is that if a charfmt exist in the character
219  //properties that it rises to the top and is exported first."
220  //In bug 119649, it is in such situation, so we need to ignore the link style when doing ms word filter exports and
221  //add the second judgement for #i24291# definition.
222  if (nWhich == RES_TXTATR_CHARFMT)
223  {
224  const SfxPoolItem* pINetItem = SearchPoolItems(rItems, RES_TXTATR_INETFMT);
225 
226  if (pINetItem)
227  {
228  const SwFormatINetFormat& rINet = static_cast<const SwFormatINetFormat&>(*pINetItem);
229  const SwCharFormat* pINetFormat = GetSwCharFormat(rINet, m_rDoc);
230  if (!pINetFormat)
231  continue;
232 
233  const SwCharFormat* pFormat = static_cast<const SwFormatCharFormat&>(*pItem).GetCharFormat();
234  ww8::PoolItems aCharItems, aINetItems;
235  GetPoolItems(pFormat->GetAttrSet(), aCharItems, false);
236  GetPoolItems(pINetFormat->GetAttrSet(), aINetItems, false);
237  for (const auto& rCharItem : aCharItems)
238  {
239  const SfxPoolItem* pCharItem = rCharItem.second;
240  sal_uInt16 nCharWhich = pCharItem->Which();
241  if (!SearchPoolItems(aINetItems, nCharWhich) && !SearchPoolItems(rItems, nCharWhich))
242  AttrOutput().OutputItem(*pCharItem);
243  }
244  continue;
245  }
246  }
247 
248  // tdf#38778 Fix output of the font in DOC run for fields
249  if (pFont &&
250  nWhich == RES_TXTATR_FIELD)
251  {
252  AttrOutput().OutputItem( *pFont );
253  }
254 
255  // tdf#66401 For Combined Characters in docx, MS Word uses half the normal font-size for the field's
256  // font-size, but only for <w:sz>. Therefore, we check if we are currently writing a field of type
257  // Combined Characters and if so, we half the font size.
258  if (bWriteCombChars &&
259  nWhich == RES_CHRATR_FONTSIZE)
260  {
261  SvxFontHeightItem fontHeight(item_cast<SvxFontHeightItem>( *pItem ));
262  fontHeight.SetHeight( fontHeight.GetHeight() / 2 );
263 
264  AttrOutput().OutputItem( fontHeight );
265  }
266  else if (nWhich == RES_CHRATR_COLOR)
267  {
268  const SvxColorItem& rColor = static_cast<const SvxColorItem&>(*pItem);
269  const SfxPoolItem* pBackgroundItem = SearchPoolItems(rItems, RES_CHRATR_BACKGROUND);
270  if (rColor.GetValue() == COL_AUTO && pBackgroundItem)
271  {
272  const SvxBrushItem& rBrushBackground = static_cast<const SvxBrushItem&>(*pBackgroundItem);
273  SvxColorItem aForeground(rBrushBackground.GetColor().IsDark() ? COL_WHITE : COL_BLACK, RES_CHRATR_COLOR);
274  AttrOutput().OutputItem(aForeground);
275  }
276  else
277  {
278  // default
279  AttrOutput().OutputItem( *pItem );
280  }
281  }
282  else
283  {
284  AttrOutput().OutputItem( *pItem );
285  }
286  }
287  }
288 }
289 
290 /*
291  * Output format as follows:
292  * - output the attributes; without parents!
293  */
294 
295 void MSWordExportBase::OutputItemSet( const SfxItemSet& rSet, bool bPapFormat, bool bChpFormat, sal_uInt16 nScript,
296  bool bExportParentItemSet )
297 {
298  if( !(bExportParentItemSet || rSet.Count()) )
299  return;
300 
301  const SfxPoolItem* pItem;
302  m_pISet = &rSet; // for double attributes
303 
304  // If frame dir is set, but not adjust, then force adjust as well
305  if ( bPapFormat && SfxItemState::SET == rSet.GetItemState( RES_FRAMEDIR, bExportParentItemSet ) )
306  {
307  // No explicit adjust set ?
308  if ( SfxItemState::SET != rSet.GetItemState( RES_PARATR_ADJUST, bExportParentItemSet ) )
309  {
310  pItem = rSet.GetItem( RES_PARATR_ADJUST, bExportParentItemSet );
311  if ( nullptr != pItem )
312  {
313  // then set the adjust used by the parent format
314  AttrOutput().OutputItem( *pItem );
315  }
316  }
317  }
318 
319  if ( bPapFormat && SfxItemState::SET == rSet.GetItemState( RES_PARATR_NUMRULE, bExportParentItemSet, &pItem ) )
320  {
321  AttrOutput().OutputItem( *pItem );
322 
323  // switch off the numbering?
324  if ( static_cast<const SwNumRuleItem*>(pItem)->GetValue().isEmpty() &&
325  SfxItemState::SET != rSet.GetItemState( RES_LR_SPACE, false) &&
326  SfxItemState::SET == rSet.GetItemState( RES_LR_SPACE, true, &pItem ) )
327  {
328  // the set the LR-Space of the parentformat!
329  AttrOutput().OutputItem( *pItem );
330  }
331  }
332 
333  ww8::PoolItems aItems;
334  GetPoolItems( rSet, aItems, bExportParentItemSet );
335  if ( bChpFormat )
336  ExportPoolItemsToCHP(aItems, nScript, nullptr);
337  if ( bPapFormat )
338  {
339  AttrOutput().MaybeOutputBrushItem(rSet);
340 
341  for ( const auto& rItem : aItems )
342  {
343  pItem = rItem.second;
344  sal_uInt16 nWhich = pItem->Which();
345  // Handle fill attributes just like frame attributes for now.
346  if ( (nWhich >= RES_PARATR_BEGIN && nWhich < RES_FRMATR_END && nWhich != RES_PARATR_NUMRULE ) ||
347  (nWhich >= XATTR_FILL_FIRST && nWhich < XATTR_FILL_LAST))
348  AttrOutput().OutputItem( *pItem );
349  }
350 
351  // Has to be called after RES_PARATR_GRABBAG is processed.
352  const XFillStyleItem* pXFillStyleItem(rSet.GetItem<XFillStyleItem>(XATTR_FILLSTYLE));
353  if (pXFillStyleItem && pXFillStyleItem->GetValue() == drawing::FillStyle_SOLID && !rSet.HasItem(RES_BACKGROUND))
354  {
355  // Construct an SvxBrushItem, as expected by the exporters.
356  std::unique_ptr<SvxBrushItem> aBrush(getSvxBrushItemFromSourceSet(rSet, RES_BACKGROUND));
357  AttrOutput().OutputItem(*aBrush);
358  }
359 #if 0
360  else
361  {
362  // note: *does not work* due to undocumented Word behavior: must be before a:ln element at least
363  AttrOutput().MaybeOutputBrushItem(rSet);
364  }
365 #endif
366  }
367  m_pISet = nullptr; // for double attributes
368 }
369 
371 {
372  //If the header/footer contains a chapter field
374  pType->GatherNodeIndex(m_aChapterFieldLocs);
375 }
376 
378 {
379  bool bRet = false;
380  if ( const SwNodeIndex* pSttIdx = rContent.GetContentIdx() )
381  {
382  SwNodeIndex aIdx( *pSttIdx, 1 );
383  SwNodeIndex aEnd( *pSttIdx->GetNode().EndOfSectionNode() );
384  sal_uLong nStart = aIdx.GetIndex();
385  sal_uLong nEnd = aEnd.GetIndex();
386  //If the header/footer contains a chapter field
387  bRet = std::any_of(m_aChapterFieldLocs.cbegin(), m_aChapterFieldLocs.cend(),
388  [nStart, nEnd](sal_uLong i) { return ( nStart <= i ) && ( i <= nEnd ); });
389  }
390  return bRet;
391 }
392 
394 {
395  if ( m_aChapterFieldLocs.empty() )
396  return false;
397 
398  const SwFrameFormat *pFormat = nullptr;
399 
400  pFormat = rFormat.GetHeader().GetHeaderFormat();
401  if ( pFormat && ContentContainsChapterField( pFormat->GetContent() ) )
402  return true;
403 
404  pFormat = rFormat.GetFooter().GetFooterFormat();
405  return pFormat && ContentContainsChapterField( pFormat->GetContent() );
406 }
407 
409 {
410  bool bNewPageDesc = false;
411  const SwPageDesc* pCurrent = SwPageDesc::GetPageDescOfNode(rNd);
412  OSL_ENSURE(pCurrent && m_pCurrentPageDesc, "Not possible surely");
413  if (m_pCurrentPageDesc && pCurrent)
414  {
415  if (pCurrent != m_pCurrentPageDesc)
416  {
417  if (m_pCurrentPageDesc->GetFollow() != pCurrent)
418  bNewPageDesc = true;
419  else
420  {
421  const SwFrameFormat& rTitleFormat = m_pCurrentPageDesc->GetFirstMaster();
422  const SwFrameFormat& rFollowFormat = pCurrent->GetMaster();
423 
424  bNewPageDesc = !IsPlausableSingleWordSection(rTitleFormat,
425  rFollowFormat);
426  }
427  m_pCurrentPageDesc = pCurrent;
428  }
429  else
430  {
431  const SwFrameFormat &rFormat = pCurrent->GetMaster();
432  bNewPageDesc = FormatHdFtContainsChapterField(rFormat);
433  }
434  }
435  return bNewPageDesc;
436 }
437 
448 void MSWordExportBase::OutputSectionBreaks( const SfxItemSet *pSet, const SwNode& rNd, bool isCellOpen )
449 {
450  if ( m_bStyDef || m_bOutKF || m_bInWriteEscher || m_bOutPageDescs )
451  return;
452 
453  m_bBreakBefore = true;
454  bool bNewPageDesc = false;
455  const SfxPoolItem* pItem=nullptr;
456  const SwFormatPageDesc *pPgDesc=nullptr;
457 
458  //Output a sectionbreak if there's a new pagedescriptor. Otherwise output a
459  //pagebreak if there is a pagebreak here, unless the new page (follow
460  //style) is different to the current one, in which case plump for a
461  //section.
462  bool bBreakSet = false;
463 
464  const SwPageDesc * pPageDesc = rNd.FindPageDesc();
465 
466  // Even if m_pCurrentPageDesc != pPageDesc ,it might be because of the different header & footer types.
467  if (m_pCurrentPageDesc != pPageDesc)
468  {
469  if (isCellOpen && ( m_pCurrentPageDesc->GetName() != pPageDesc->GetName() ))
470  {
471  /*
472  * If Table cell is open and page header types are different
473  * set pSet to NULL as we don't want to add any section breaks inside a table.
474  */
475  pSet = nullptr;
476  }
477  else if (!sw::util::IsPlausableSingleWordSection(m_pCurrentPageDesc->GetFirstMaster(), pPageDesc->GetMaster()))
478  {
479  bBreakSet = true;
480  bNewPageDesc = true;
481  m_pCurrentPageDesc = pPageDesc;
482  }
483  }
484 
485  if ( pSet && pSet->Count() )
486  {
487  if ( SfxItemState::SET == pSet->GetItemState( RES_PAGEDESC, false, &pItem ) &&
488  static_cast<const SwFormatPageDesc*>(pItem)->GetRegisteredIn() != nullptr)
489  {
490  bBreakSet = true;
491  bNewPageDesc = true;
492  pPgDesc = static_cast<const SwFormatPageDesc*>(pItem);
493  m_pCurrentPageDesc = pPgDesc->GetPageDesc();
494  }
495  else if ( SfxItemState::SET == pSet->GetItemState( RES_BREAK, false, &pItem ) )
496  {
497  // Word does not like hard break attributes in some table cells
498  bool bRemoveHardBreakInsideTable = false;
499  if ( m_bOutTable )
500  {
501  const SwTableNode* pTableNode = rNd.FindTableNode();
502  if ( pTableNode )
503  {
504  const SwTableBox* pBox = rNd.GetTableBox();
505  const SwTableLine* pLine = pBox ? pBox->GetUpper() : nullptr;
506  // but only for non-complex tables
507  if ( pLine && !pLine->GetUpper() )
508  {
509  // check if box is not first in that line:
510  if ( 0 < pLine->GetBoxPos( pBox ) && pBox->GetSttNd() )
511  {
512  bRemoveHardBreakInsideTable = true;
513  }
514  }
515  }
516  }
517  bBreakSet = true;
518 
519  if ( !bRemoveHardBreakInsideTable )
520  {
521  OSL_ENSURE(m_pCurrentPageDesc, "should not be possible");
522  /*
523  If because of this pagebreak the page desc following the page
524  break is the follow style of the current page desc then output a
525  section break using that style instead. At least in those cases
526  we end up with the same style in word and writer, nothing can be
527  done when it happens when we get a new pagedesc because we
528  overflow from the first page style.
529  */
530  if ( m_pCurrentPageDesc )
531  {
532  // #i76301# - assure that there is a page break before set at the node.
533  const SvxFormatBreakItem* pBreak = dynamic_cast<const SvxFormatBreakItem*>(pItem);
534  if ( pBreak &&
535  pBreak->GetBreak() == SvxBreak::PageBefore )
536  {
537  bNewPageDesc |= SetCurrentPageDescFromNode( rNd );
538  }
539  }
540  if ( !bNewPageDesc )
541  AttrOutput().OutputItem( *pItem );
542  }
543  }
544  }
545 
546  /*
547  #i9301#
548  No explicit page break, lets see if the style had one and we've moved to a
549  new page style because of it, if we have to then we take the opportunity to
550  set the equivalent word section here. We *could* do it for every paragraph
551  that moves onto a new page because of layout, but that would be insane.
552  */
553  bool bHackInBreak = false;
554  if ( !bBreakSet )
555  {
556  if ( const SwContentNode *pNd = rNd.GetContentNode() )
557  {
558  const SvxFormatBreakItem &rBreak =
559  ItemGet<SvxFormatBreakItem>( *pNd, RES_BREAK );
560  if ( rBreak.GetBreak() == SvxBreak::PageBefore )
561  bHackInBreak = true;
562  else
563  { // Even a pagedesc item is set, the break item can be set 'NONE',
564  // but a pagedesc item is an implicit page break before...
565  const SwFormatPageDesc &rPageDesc =
566  ItemGet<SwFormatPageDesc>( *pNd, RES_PAGEDESC );
567  if ( rPageDesc.KnowsPageDesc() )
568  bHackInBreak = true;
569  }
570  }
571  }
572 
573  if ( bHackInBreak )
574  {
575  OSL_ENSURE( m_pCurrentPageDesc, "should not be possible" );
576  if ( m_pCurrentPageDesc )
577  bNewPageDesc = SetCurrentPageDescFromNode( rNd );
578  }
579 
580  if ( bNewPageDesc && m_pCurrentPageDesc )
581  {
582  PrepareNewPageDesc( pSet, rNd, pPgDesc, m_pCurrentPageDesc );
583  }
584  m_bBreakBefore = false;
585 }
586 
587 // #i76300#
589 {
590  bool bRet = false;
591 
592  if ( pNd &&
593  m_pCurrentPageDesc &&
594  m_pCurrentPageDesc != m_pCurrentPageDesc->GetFollow() )
595  {
596  PrepareNewPageDesc( pSet, *pNd, nullptr, m_pCurrentPageDesc->GetFollow() );
597  bRet = true;
598  }
599 
600  return bRet;
601 }
602 
604 {
605  const SwSectionFormat* pFormat = nullptr;
606  const SwSectionNode* pSect = rNd.FindSectionNode();
607  if ( pSect &&
608  SectionType::Content == pSect->GetSection().GetType() )
609  {
610  pFormat = pSect->GetSection().GetFormat();
611  }
612 
613  return pFormat;
614 }
615 
617 {
618  const SwFormatLineNumber* pNItem = nullptr;
619  if ( pSet )
620  {
621  pNItem = &( ItemGet<SwFormatLineNumber>( *pSet, RES_LINENUMBER ) );
622  }
623  else if ( const SwContentNode *pNd = rNd.GetContentNode() )
624  {
625  pNItem = &( ItemGet<SwFormatLineNumber>( *pNd, RES_LINENUMBER ) );
626  }
627 
628  return pNItem? pNItem->GetStartValue() : 0;
629 }
630 
632  const SwNode& rNd,
633  const SwFormatPageDesc* pNewPgDescFormat,
634  const SwPageDesc* pNewPgDesc )
635 {
636  // The PageDescs will only be inserted in WW8Writer::pSepx with the corresponding
637  // position by the occurrences of PageDesc attributes. The construction and
638  // output of the attributes and header/footer of the PageDesc are done
639  // after the main text and its attributes.
640 
641  sal_uLong nFcPos = ReplaceCr( msword::PageBreak ); // Page/Section-Break
642 
643  // actually nothing is outputted here, rather the arrays aCps, aSects
644  // accordingly completed
645  if ( !nFcPos )
646  return;
647 
648  const SwSectionFormat* pFormat = GetSectionFormat( rNd );
649  const sal_uLong nLnNm = GetSectionLineNo( pSet, rNd );
650 
651  OSL_ENSURE( pNewPgDescFormat || pNewPgDesc, "Neither page desc format nor page desc provided." );
652 
653  if ( pNewPgDescFormat )
654  {
655  pSepx->AppendSep( Fc2Cp( nFcPos ), *pNewPgDescFormat, rNd, pFormat, nLnNm );
656  }
657  else if ( pNewPgDesc )
658  {
659  pSepx->AppendSep( Fc2Cp( nFcPos ), pNewPgDesc, rNd, pFormat, nLnNm );
660  }
661 }
662 
663 void MSWordExportBase::CorrectTabStopInSet( SfxItemSet& rSet, sal_Int32 nAbsLeft )
664 {
666  if (!pItem)
667  return;
668 
669  // then it must be corrected for the output
670  SvxTabStopItem aTStop(*pItem);
671  for ( sal_uInt16 nCnt = 0; nCnt < aTStop.Count(); ++nCnt )
672  {
673  SvxTabStop& rTab = const_cast<SvxTabStop&>(aTStop[ nCnt ]);
674  if ( SvxTabAdjust::Default != rTab.GetAdjustment() &&
675  rTab.GetTabPos() >= nAbsLeft )
676  {
677  rTab.GetTabPos() -= nAbsLeft;
678  }
679  else
680  {
681  aTStop.Remove( nCnt );
682  --nCnt;
683  }
684  }
685  rSet.Put( aTStop );
686 }
687 
688 sal_uInt8 WW8Export::GetNumId( sal_uInt16 eNumType )
689 {
690  sal_uInt8 nRet = 0;
691  switch( eNumType )
692  {
694  case SVX_NUM_CHARS_UPPER_LETTER_N: nRet = 3; break;
696  case SVX_NUM_CHARS_LOWER_LETTER_N: nRet = 4; break;
697  case SVX_NUM_ROMAN_UPPER: nRet = 1; break;
698  case SVX_NUM_ROMAN_LOWER: nRet = 2; break;
699 
700  case SVX_NUM_BITMAP:
701  case SVX_NUM_CHAR_SPECIAL: nRet = 23; break;
702 
703  // nothing, WW does the same (undocumented)
704  case SVX_NUM_NUMBER_NONE: nRet = 0xff; break;
706  // 0x09, msonfcChiManSty
707  nRet = 9;
708  break;
709  case SVX_NUM_ARABIC_ZERO:
710  // 0x16, msonfcArabicLZ
711  nRet = 22;
712  break;
713  }
714  return nRet;
715 }
716 
718 {
719  if ( nLvl >= WW8ListManager::nMaxLevel )
720  nLvl = WW8ListManager::nMaxLevel-1;
721 
722  // write sprmPOutLvl sprmPIlvl and sprmPIlfo
723  SwWW8Writer::InsUInt16( *m_rWW8Export.pO, NS_sprm::POutLvl::val );
724  m_rWW8Export.pO->push_back( nLvl );
725  SwWW8Writer::InsUInt16( *m_rWW8Export.pO, NS_sprm::PIlvl::val );
726  m_rWW8Export.pO->push_back( nLvl );
727  SwWW8Writer::InsUInt16( *m_rWW8Export.pO, NS_sprm::PIlfo::val );
728  SwWW8Writer::InsUInt16( *m_rWW8Export.pO,
729  1 + m_rWW8Export.GetNumberingId(*m_rWW8Export.m_rDoc.GetOutlineNumRule()) );
730 }
731 
732 // #i77805#
734 {
735  bool bRet( false );
736 
737  //If there is no numbering on this fmt, but its parent was outline
738  //numbered, then in writer this is no inheritied, but in word it would
739  //be, so we must export "no numbering" and "body level" to make word
740  //behave like writer (see #i25755)
741  if (SfxItemState::SET != rFormat.GetItemState(RES_PARATR_NUMRULE, false))
742  {
743  if (const SwFormat *pParent = rFormat.DerivedFrom())
744  {
745  if (static_cast<const SwTextFormatColl*>(pParent)->IsAssignedToListLevelOfOutlineStyle())
746  {
748  pO->push_back(sal_uInt8(9));
750  SwWW8Writer::InsUInt16(*pO, 0);
751 
752  bRet = true;
753  }
754  }
755  }
756 
757  return bRet;
758 }
759 
760 void MSWordExportBase::OutputFormat( const SwFormat& rFormat, bool bPapFormat, bool bChpFormat, bool bFlyFormat )
761 {
762  bool bCallOutSet = true;
763  const sw::BroadcastingModify* pOldMod = m_pOutFormatNode;
764  m_pOutFormatNode = &rFormat;
765 
766  switch( rFormat.Which() )
767  {
768  case RES_CONDTXTFMTCOLL:
769  case RES_TXTFMTCOLL:
770  if( bPapFormat )
771  {
772  int nLvl = MAXLEVEL;
773 
774  if (static_cast<const SwTextFormatColl&>(rFormat).IsAssignedToListLevelOfOutlineStyle())
775  nLvl = static_cast<const SwTextFormatColl&>(rFormat).GetAssignedOutlineStyleLevel();
776 
777  if (nLvl >= 0 && nLvl < MAXLEVEL)
778  {
779  //if outline numbered
780  // if Write StyleDefinition then write the OutlineRule
781  const SwNumFormat& rNFormat = m_rDoc.GetOutlineNumRule()->Get( static_cast<sal_uInt16>( nLvl ) );
782  if ( m_bStyDef )
783  AttrOutput().OutlineNumbering(static_cast<sal_uInt8>(nLvl));
784 
785  if ( rNFormat.GetPositionAndSpaceMode() ==
787  rNFormat.GetAbsLSpace() )
788  {
789  SfxItemSet aSet( rFormat.GetAttrSet() );
790  SvxLRSpaceItem aLR(
791  ItemGet<SvxLRSpaceItem>(aSet, RES_LR_SPACE));
792 
793  aLR.SetTextLeft( aLR.GetTextLeft() + rNFormat.GetAbsLSpace() );
794  aLR.SetTextFirstLineOffset( GetWordFirstLineOffset(rNFormat));
795 
796  aSet.Put( aLR );
797  CorrectTabStopInSet( aSet, rNFormat.GetAbsLSpace() );
798  OutputItemSet( aSet, bPapFormat, bChpFormat,
799  i18n::ScriptType::LATIN, m_bExportModeRTF);
800  bCallOutSet = false;
801  }
802  }
803  else
804  {
805  //otherwise we might have to remove outline numbering from
806  //what gets exported if the parent style was outline numbered
807  // #i77805#
808  // If inherited outline numbering is suppress, the left/right
809  // margins has to be exported explicitly.
810  if ( m_bStyDef && DisallowInheritingOutlineNumbering(rFormat) )
811  {
812  SfxItemSet aSet( rFormat.GetAttrSet() );
813  const SvxLRSpaceItem& aLR(
814  ItemGet<SvxLRSpaceItem>(aSet, RES_LR_SPACE));
815  aSet.Put( aLR );
816  OutputItemSet( aSet, bPapFormat, bChpFormat,
817  css::i18n::ScriptType::LATIN, m_bExportModeRTF);
818  bCallOutSet = false;
819  }
820  }
821  }
822  break;
823 
824  case RES_CHRFMT:
825  break;
826  case RES_FLYFRMFMT:
827  if (bFlyFormat)
828  {
829  OSL_ENSURE(m_pParentFrame, "No parent frame, all broken");
830 
831  if (m_pParentFrame)
832  {
833  const SwFrameFormat &rFrameFormat = m_pParentFrame->GetFrameFormat();
834 
836  RES_FRMATR_END-1,
838  aSet.Set(rFrameFormat.GetAttrSet());
839 
840  // Fly as character becomes a paragraph bound
841  // now set the distance to paragraph margin
842  if (m_pFlyOffset)
843  {
844  aSet.Put(SwFormatHoriOrient(m_pFlyOffset->X()));
845  aSet.Put(SwFormatVertOrient(m_pFlyOffset->Y()));
846  SwFormatAnchor aAnchor(rFrameFormat.GetAnchor());
847  aAnchor.SetType(m_eNewAnchorType);
848  aSet.Put(aAnchor);
849  }
850 
851  if (SfxItemState::SET != aSet.GetItemState(RES_SURROUND))
852  aSet.Put(SwFormatSurround(css::text::WrapTextMode_NONE));
853 
854  const XFillStyleItem* pXFillStyleItem(rFrameFormat.GetAttrSet().GetItem<XFillStyleItem>(XATTR_FILLSTYLE));
855  if (pXFillStyleItem)
856  {
857  switch (pXFillStyleItem->GetValue())
858  {
859  case drawing::FillStyle_NONE:
860  break;
861  case drawing::FillStyle_SOLID:
862  {
863  // Construct an SvxBrushItem, as expected by the exporters.
864  std::unique_ptr<SvxBrushItem> aBrush(getSvxBrushItemFromSourceSet(rFrameFormat.GetAttrSet(), RES_BACKGROUND));
865  aSet.Put(*aBrush);
866  break;
867  }
868  default:
869  break;
870  }
871  }
872 
873  m_bOutFlyFrameAttrs = true;
874  //script doesn't matter if not exporting chp
875  OutputItemSet(aSet, true, false,
876  i18n::ScriptType::LATIN, m_bExportModeRTF);
877  m_bOutFlyFrameAttrs = false;
878 
879  bCallOutSet = false;
880  }
881  }
882  break;
883  case RES_FRMFMT:
884  break;
885  default:
886  OSL_ENSURE( false, "Which format is exported here?" );
887  break;
888  }
889 
890  if( bCallOutSet )
891  OutputItemSet( rFormat.GetAttrSet(), bPapFormat, bChpFormat,
892  i18n::ScriptType::LATIN, m_bExportModeRTF);
893  m_pOutFormatNode = pOldMod;
894 }
895 
896 bool MSWordExportBase::HasRefToAttr(const OUString& rName)
897 {
899  std::vector<SwGetRefField*> vpRFields;
900  pType->GatherRefFields(vpRFields, REF_SETREFATTR);
901  return std::any_of(vpRFields.begin(), vpRFields.end(),
902  [rName](SwGetRefField* pF) { return rName == pF->GetSetRefName(); });
903 }
904 
905 bool MSWordExportBase::HasRefToFootOrEndnote(const bool isEndNote, const sal_uInt16 nSeqNo)
906 {
908  std::vector<SwGetRefField*> vpRFields;
909  pType->GatherRefFields(vpRFields, isEndNote ? REF_ENDNOTE : REF_FOOTNOTE);
910  return std::any_of(vpRFields.begin(), vpRFields.end(),
911  [nSeqNo](SwGetRefField* pF) { return nSeqNo == pF->GetSeqNo(); });
912 }
913 
914 OUString MSWordExportBase::GetBookmarkName( sal_uInt16 nTyp, const OUString* pName, sal_uInt16 nSeqNo )
915 {
916  OUString sRet;
917  switch ( nTyp )
918  {
919  case REF_SETREFATTR:
920  if ( pName )
921  {
922  sRet = "Ref_" + *pName;
923  }
924  break;
925  case REF_SEQUENCEFLD:
926  {
927  assert(pName);
928  sRet = "Ref_" + *pName;
929  break;
930  }
931  case REF_BOOKMARK:
932  if ( pName )
933  sRet = *pName;
934  break;
935  case REF_OUTLINE:
936  break; // ???
937  case REF_FOOTNOTE:
938  sRet = "_RefF" + OUString::number( nSeqNo );
939  break;
940  case REF_ENDNOTE:
941  sRet = "_RefE" + OUString::number( nSeqNo );
942  break;
943  }
944  return BookmarkToWord( sRet ); // #i43956# - encode bookmark accordingly
945 }
946 
947 /* File CHRATR.HXX: */
948 void WW8AttributeOutput::RTLAndCJKState( bool bIsRTL, sal_uInt16 nScript )
949 {
950  if (bIsRTL)
951  {
952  if( m_rWW8Export.m_rDoc.GetDocumentType() != SwDoc::DOCTYPE_MSWORD )
953  {
954  m_rWW8Export.InsUInt16( NS_sprm::CFBiDi::val );
955  m_rWW8Export.pO->push_back( sal_uInt8(1) );
956  }
957  }
958 
959  // #i46087# patch from james_clark; complex texts needs the undocumented SPRM CComplexScript with param 0x81.
960  if (nScript == i18n::ScriptType::COMPLEX && !bIsRTL)
961  {
962  m_rWW8Export.InsUInt16( NS_sprm::CFComplexScripts::val );
963  m_rWW8Export.pO->push_back( sal_uInt8(0x81) );
964  m_rWW8Export.pDop->bUseThaiLineBreakingRules = true;
965  }
966 }
967 
969 {
970  m_rWW8Export.m_pPapPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell() - (mbOnTOXEnding?2:0), m_rWW8Export.pO->size(), m_rWW8Export.pO->data() );
971  mbOnTOXEnding = false;
972  m_rWW8Export.pO->clear();
973 
974  if ( pTextNodeInfoInner )
975  {
976  if ( pTextNodeInfoInner->isEndOfLine() )
977  {
978  TableRowEnd( pTextNodeInfoInner->getDepth() );
979 
980  SVBT16 nSty;
981  ShortToSVBT16( 0, nSty );
982  m_rWW8Export.pO->insert( m_rWW8Export.pO->end(), nSty, nSty+2 ); // Style #
983  TableInfoRow( pTextNodeInfoInner );
984  m_rWW8Export.m_pPapPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), m_rWW8Export.pO->size(), m_rWW8Export.pO->data());
985  m_rWW8Export.pO->clear();
986  }
987  }
988 
989  // Clear bookmarks of the current paragraph
990  m_aBookmarksOfParagraphStart.clear();
991  m_aBookmarksOfParagraphEnd.clear();
992 }
993 
995 {
996  WW8_WrPlcField* pCurrentFields = m_rWW8Export.CurrentFieldPlc();
997  m_nFieldResults = pCurrentFields ? pCurrentFields->ResultCount() : 0;
998 }
999 
1000 void WW8AttributeOutput::StartRun( const SwRedlineData* pRedlineData, sal_Int32 nPos, bool /*bSingleEmptyRun*/ )
1001 {
1002  if (pRedlineData)
1003  {
1004  const OUString &rComment = pRedlineData->GetComment();
1005  //Only possible to export to main text
1006  if (!rComment.isEmpty() && (m_rWW8Export.m_nTextTyp == TXT_MAINTEXT))
1007  {
1008  if (m_rWW8Export.m_pAtn->IsNewRedlineComment(pRedlineData))
1009  {
1010  m_rWW8Export.m_pAtn->Append( m_rWW8Export.Fc2Cp( m_rWW8Export.Strm().Tell() ), pRedlineData );
1011  m_rWW8Export.WritePostItBegin( m_rWW8Export.pO.get() );
1012  }
1013  }
1014  }
1015 
1017  auto aRange = m_aBookmarksOfParagraphStart.equal_range(nPos);
1018  for( auto aIter = aRange.first; aIter != aRange.second; ++aIter)
1019  {
1020  GetExport().AppendBookmark(BookmarkToWord(aIter->second));
1021  }
1022 }
1023 
1025 {
1026  mbOnTOXEnding = true;
1027 }
1028 
1029 void WW8AttributeOutput::EndRun( const SwTextNode* /*pNode*/, sal_Int32 nPos, bool bLastRun )
1030 {
1032  auto aRange = m_aBookmarksOfParagraphEnd.equal_range(nPos);
1033  for( auto aIter = aRange.first; aIter != aRange.second; ++aIter)
1034  {
1035  if(bLastRun)
1036  GetExport().AppendBookmarkEndWithCorrection(BookmarkToWord(aIter->second));
1037  else
1038  GetExport().AppendBookmark(BookmarkToWord(aIter->second));
1039  }
1040 }
1041 
1043 {
1044  Redline( pRedlineData );
1045 
1046  WW8_WrPlcField* pCurrentFields = m_rWW8Export.CurrentFieldPlc();
1047  sal_uInt16 nNewFieldResults = pCurrentFields ? pCurrentFields->ResultCount() : 0;
1048 
1049  bool bExportedFieldResult = ( m_nFieldResults != nNewFieldResults );
1050 
1051  // If we have exported a field result, then we will have been forced to
1052  // split up the text into a 0x13, 0x14, <result> 0x15 sequence with the
1053  // properties forced out at the end of the result, so the 0x15 itself
1054  // should remain clean of all other attributes to avoid #iXXXXX#
1055  if ( !bExportedFieldResult )
1056  {
1057  m_rWW8Export.m_pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(),
1058  m_rWW8Export.pO->size(), m_rWW8Export.pO->data() );
1059  }
1060  m_rWW8Export.pO->clear();
1061 }
1062 
1063 void WW8AttributeOutput::RunText( const OUString& rText, rtl_TextEncoding eCharSet )
1064 {
1065  RawText(rText, eCharSet);
1066 }
1067 
1068 void WW8AttributeOutput::RawText(const OUString& rText, rtl_TextEncoding)
1069 {
1070  m_rWW8Export.OutSwString(rText, 0, rText.getLength());
1071 }
1072 
1074 {
1075  if (!m_rWW8Export.pO->empty() || bForce)
1076  {
1077  m_rWW8Export.m_pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(),
1078  m_rWW8Export.pO->size(), m_rWW8Export.pO->data() );
1079  m_rWW8Export.pO->clear();
1080  }
1081 }
1082 
1083 void WW8AttributeOutput::ParagraphStyle( sal_uInt16 nStyle )
1084 {
1085  OSL_ENSURE( m_rWW8Export.pO->empty(), " pO is not empty at line end" );
1086 
1087  SVBT16 nSty;
1088  ShortToSVBT16( nStyle, nSty );
1089  m_rWW8Export.pO->insert( m_rWW8Export.pO->end(), nSty, nSty+2 ); // style #
1090 }
1091 
1093 {
1094  m_rWW8Export.InsUInt16( 8 == nId ? NS_sprm::CFDStrike::val : NS_sprm::CFBold::val + nId );
1095 
1096  m_rWW8Export.pO->push_back( bVal ? 1 : 0 );
1097 }
1098 
1100 {
1101  OSL_ENSURE( nId <= 1, "out of range" );
1102  if (nId > 1)
1103  return;
1104 
1105  m_rWW8Export.InsUInt16( NS_sprm::CFBoldBi::val + nId );
1106  m_rWW8Export.pO->push_back( bVal ? 1 : 0 );
1107 }
1108 
1110 {
1111  sal_uInt16 nFontID = m_rWW8Export.GetId( rFont );
1112 
1113  m_rWW8Export.InsUInt16( NS_sprm::CRgFtc0::val );
1114  m_rWW8Export.InsUInt16( nFontID );
1115  m_rWW8Export.InsUInt16( NS_sprm::CRgFtc2::val );
1116 
1117  m_rWW8Export.InsUInt16( nFontID );
1118 }
1119 
1121 {
1122  sal_uInt16 nFontID = m_rWW8Export.GetId( rFont );
1123  m_rWW8Export.InsUInt16( NS_sprm::CFtcBi::val );
1124  m_rWW8Export.InsUInt16( nFontID );
1125 }
1126 
1128 {
1129  sal_uInt16 nFontID = m_rWW8Export.GetId( rFont );
1130  m_rWW8Export.InsUInt16( NS_sprm::CRgFtc1::val );
1131  m_rWW8Export.InsUInt16( nFontID );
1132 }
1133 
1135 {
1136  OutputWW8AttributeCTL( 0, WEIGHT_BOLD == rWeight.GetWeight());
1137 }
1138 
1140 {
1141  OutputWW8AttributeCTL( 1, ITALIC_NONE != rPosture.GetPosture() );
1142 }
1143 
1145 {
1146  OutputWW8Attribute( 1, ITALIC_NONE != rPosture.GetPosture() );
1147 }
1148 
1150 {
1151  OutputWW8Attribute( 0, WEIGHT_BOLD == rWeight.GetWeight() );
1152 }
1153 
1154 // Shadowed and Contour are not in WW-UI. JP: ??
1156 {
1157  OutputWW8Attribute( 3, rContour.GetValue() );
1158 }
1159 
1161 {
1162  OutputWW8Attribute( 4, rShadow.GetValue() );
1163 }
1164 
1166 {
1167  m_rWW8Export.InsUInt16( NS_sprm::CDxaSpace::val );
1168 
1169  m_rWW8Export.InsUInt16( rKerning.GetValue() );
1170 }
1171 
1173 {
1174  m_rWW8Export.InsUInt16( NS_sprm::CHpsKern::val );
1175 
1176  m_rWW8Export.InsUInt16( rAutoKern.GetValue() ? 2 : 0 );
1177 }
1178 
1180 {
1181  m_rWW8Export.InsUInt16( NS_sprm::CSfxText::val );
1182  // At the moment the only animated text effect we support is blinking
1183  m_rWW8Export.pO->push_back( rBlink.GetValue() ? 2 : 0 );
1184 }
1185 
1187 {
1188  FontStrikeout eSt = rCrossed.GetStrikeout();
1189  if ( STRIKEOUT_DOUBLE == eSt )
1190  {
1191  OutputWW8Attribute( 8, true );
1192  return;
1193  }
1194  if ( STRIKEOUT_NONE != eSt )
1195  {
1196  OutputWW8Attribute( 2, true );
1197  return;
1198  }
1199 
1200  // otherwise both off
1201  OutputWW8Attribute( 8, false );
1202  OutputWW8Attribute( 2, false );
1203 }
1204 
1206 {
1207  SvxCaseMap eSt = rCaseMap.GetValue();
1208  switch ( eSt )
1209  {
1210  case SvxCaseMap::SmallCaps:
1211  OutputWW8Attribute( 5, true );
1212  return;
1213  case SvxCaseMap::Uppercase:
1214  OutputWW8Attribute( 6, true );
1215  return;
1216  case SvxCaseMap::Capitalize:
1217  // no such feature in word
1218  break;
1219  default:
1220  // otherwise both off
1221  OutputWW8Attribute( 5, false );
1222  OutputWW8Attribute( 6, false );
1223  return;
1224  }
1225 }
1226 
1228 {
1229  OutputWW8Attribute( 7, rHidden.GetValue() );
1230 }
1231 
1232 void WW8AttributeOutput::CharBorder( const SvxBorderLine* pAllBorder, const sal_uInt16 /*nDist*/, const bool bShadow )
1233 {
1234  WW8Export::Out_BorderLine( *m_rWW8Export.pO, pAllBorder, 0, NS_sprm::CBrc80::val, NS_sprm::CBrc::val, bShadow );
1235 }
1236 
1238 {
1239  if (rBrush.GetColor() != COL_TRANSPARENT)
1240  {
1241  sal_uInt8 nColor = msfilter::util::TransColToIco( rBrush.GetColor() );
1242  // sprmCHighlight
1243  m_rWW8Export.InsUInt16( NS_sprm::CHighlight::val );
1244  m_rWW8Export.pO->push_back( nColor );
1245  }
1246 }
1247 
1249 {
1250  m_rWW8Export.InsUInt16( NS_sprm::CKul::val );
1251 
1252  const SfxPoolItem* pItem = m_rWW8Export.HasItem( RES_CHRATR_WORDLINEMODE );
1253  bool bWord = false;
1254  if (pItem)
1255  bWord = static_cast<const SvxWordLineModeItem*>(pItem)->GetValue();
1256 
1257  // WW95 - parameters: 0 = none, 1 = single, 2 = by Word,
1258  // 3 = double, 4 = dotted, 5 = hidden
1259  // WW97 - additional parameters:
1260  // 6 = thick, 7 = dash, 8 = dot(not used)
1261  // 9 = dotdash 10 = dotdotdash, 11 = wave
1262  sal_uInt8 b = 0;
1263  switch ( rUnderline.GetLineStyle() )
1264  {
1265  case LINESTYLE_SINGLE:
1266  b = bWord ? 2 : 1;
1267  break;
1268  case LINESTYLE_BOLD:
1269  b = 6;
1270  break;
1271  case LINESTYLE_DOUBLE:
1272  b = 3;
1273  break;
1274  case LINESTYLE_DOTTED:
1275  b = 4;
1276  break;
1277  case LINESTYLE_DASH:
1278  b = 7;
1279  break;
1280  case LINESTYLE_DASHDOT:
1281  b = 9;
1282  break;
1283  case LINESTYLE_DASHDOTDOT:
1284  b = 10;
1285  break;
1286  case LINESTYLE_WAVE:
1287  b = 11;
1288  break;
1289  // new in WW2000
1290  case LINESTYLE_BOLDDOTTED:
1291  b = 20;
1292  break;
1293  case LINESTYLE_BOLDDASH:
1294  b = 23;
1295  break;
1296  case LINESTYLE_LONGDASH:
1297  b = 39;
1298  break;
1300  b = 55;
1301  break;
1302  case LINESTYLE_BOLDDASHDOT:
1303  b = 25;
1304  break;
1306  b = 26;
1307  break;
1308  case LINESTYLE_BOLDWAVE:
1309  b = 27;
1310  break;
1311  case LINESTYLE_DOUBLEWAVE:
1312  b = 43;
1313  break;
1314  case LINESTYLE_NONE:
1315  b = 0;
1316  break;
1317  default:
1318  OSL_ENSURE( rUnderline.GetLineStyle() == LINESTYLE_NONE, "Unhandled underline type" );
1319  break;
1320  }
1321 
1322  m_rWW8Export.pO->push_back( b );
1323  Color aColor = rUnderline.GetColor();
1324  if( aColor != COL_TRANSPARENT )
1325  {
1326  m_rWW8Export.InsUInt16( NS_sprm::CCvUl::val );
1327 
1328  m_rWW8Export.InsUInt32( wwUtility::RGBToBGR( aColor ) );
1329  }
1330 }
1331 
1333 {
1334  sal_uInt16 nId = 0;
1335  switch ( rLanguage.Which() )
1336  {
1337  case RES_CHRATR_LANGUAGE:
1339  break;
1342  break;
1344  nId = NS_sprm::CLidBi::val;
1345  break;
1346  }
1347 
1348  if ( !nId )
1349  return;
1350 
1351  // use sprmCRgLid0_80 rather than sprmCLid
1352  m_rWW8Export.InsUInt16( nId );
1353  m_rWW8Export.InsUInt16( static_cast<sal_uInt16>(rLanguage.GetLanguage()) );
1354 
1355  // Word 2000 and above apparently require both old and new versions of
1356  // these sprms to be set, without it spellchecking doesn't work
1357  if ( nId == NS_sprm::CRgLid0_80::val )
1358  {
1359  m_rWW8Export.InsUInt16( NS_sprm::CRgLid0::val );
1360  m_rWW8Export.InsUInt16( static_cast<sal_uInt16>(rLanguage.GetLanguage()) );
1361  }
1362  else if ( nId == NS_sprm::CRgLid1_80::val )
1363  {
1364  m_rWW8Export.InsUInt16( NS_sprm::CRgLid1::val );
1365  m_rWW8Export.InsUInt16( static_cast<sal_uInt16>(rLanguage.GetLanguage()) );
1366  }
1367 }
1368 
1370 {
1371  sal_uInt8 b = 0xFF;
1372  short nEsc = rEscapement.GetEsc(), nProp = rEscapement.GetProportionalHeight();
1373  if ( !nEsc )
1374  {
1375  b = 0;
1376  nEsc = 0;
1377  nProp = 100;
1378  }
1379  else if ( DFLT_ESC_PROP == nProp || nProp < 1 || nProp > 100 )
1380  {
1381  if ( DFLT_ESC_SUB == nEsc || DFLT_ESC_AUTO_SUB == nEsc )
1382  b = 2;
1383  else if ( DFLT_ESC_SUPER == nEsc || DFLT_ESC_AUTO_SUPER == nEsc )
1384  b = 1;
1385  }
1386  else if ( DFLT_ESC_AUTO_SUPER == nEsc )
1387  {
1388  // Raised by the differences between the ascenders (ascent = baseline to top of highest letter).
1389  // The ascent is generally about 80% of the total font height.
1390  // That is why DFLT_ESC_PROP (58) leads to 33% (DFLT_ESC_SUPER)
1391  nEsc = .8 * (100 - nProp);
1392  }
1393  else if ( DFLT_ESC_AUTO_SUB == nEsc )
1394  {
1395  // Lowered by the differences between the descenders (descent = baseline to bottom of lowest letter).
1396  // The descent is generally about 20% of the total font height.
1397  // That is why DFLT_ESC_PROP (58) leads to 8% (DFLT_ESC_SUB)
1398  nEsc = .2 * -(100 - nProp);
1399  }
1400 
1401  if ( 0xFF != b )
1402  {
1403  m_rWW8Export.InsUInt16( NS_sprm::CIss::val );
1404 
1405  m_rWW8Export.pO->push_back( b );
1406  }
1407 
1408  if ( 0 != b && 0xFF != b )
1409  return;
1410 
1411  double fHeight = m_rWW8Export.GetItem( RES_CHRATR_FONTSIZE ).GetHeight();
1412  m_rWW8Export.InsUInt16( NS_sprm::CHpsPos::val );
1413 
1414  m_rWW8Export.InsUInt16(static_cast<short>( round(fHeight * nEsc / 1000) ));
1415 
1416  if( 100 != nProp || !b )
1417  {
1418  m_rWW8Export.InsUInt16( NS_sprm::CHps::val );
1419  m_rWW8Export.InsUInt16(msword_cast<sal_uInt16>( round(fHeight * nProp / 1000) ));
1420  }
1421 }
1422 
1424 {
1425  sal_uInt16 nId = 0;
1426  switch ( rHeight.Which() )
1427  {
1428  case RES_CHRATR_FONTSIZE:
1430  nId = NS_sprm::CHps::val;
1431  break;
1433  nId = NS_sprm::CHpsBi::val;
1434  break;
1435  }
1436 
1437  if ( nId )
1438  {
1439  m_rWW8Export.InsUInt16( nId );
1440 
1441  m_rWW8Export.InsUInt16( static_cast<sal_uInt16>(( rHeight.GetHeight() + 5 ) / 10 ) );
1442  }
1443 }
1444 
1446 {
1447  m_rWW8Export.InsUInt16( NS_sprm::CCharScale::val );
1448  m_rWW8Export.InsUInt16( rScaleWidth.GetValue() );
1449 }
1450 
1452 {
1453  sal_uInt16 nId;
1454  switch ( rRelief.GetValue() )
1455  {
1456  case FontRelief::Embossed: nId = NS_sprm::CFEmboss::val; break;
1457  case FontRelief::Engraved: nId = NS_sprm::CFImprint::val; break;
1458  default: nId = 0; break;
1459  }
1460 
1461  if( nId )
1462  {
1463  m_rWW8Export.InsUInt16( nId );
1464  m_rWW8Export.pO->push_back( sal_uInt8(0x81) );
1465  }
1466  else
1467  {
1468  // switch both flags off
1469  m_rWW8Export.InsUInt16( NS_sprm::CFEmboss::val );
1470  m_rWW8Export.pO->push_back( sal_uInt8(0x0) );
1471  m_rWW8Export.InsUInt16( NS_sprm::CFImprint::val );
1472  m_rWW8Export.pO->push_back( sal_uInt8(0x0) );
1473  }
1474 }
1475 
1477 {
1478  const SfxInt16Item& rAttr = static_cast<const SfxInt16Item&>(rHt);
1479  if( rAttr.GetValue() == 1 )
1480  {
1481  m_rWW8Export.InsUInt16(0x85a);
1482  m_rWW8Export.pO->push_back(sal_uInt8(1));
1483  }
1484 }
1485 
1487 {
1488  const SfxInt16Item& rAttr = static_cast<const SfxInt16Item&>(rHt);
1489  m_rWW8Export.InsUInt16(0x286F);
1490  m_rWW8Export.pO->push_back(static_cast<sal_uInt8>(rAttr.GetValue()));
1491 }
1492 
1494 {
1495  // #i28331# - check that a Value is set
1496  if ( !rRotate.GetValue() )
1497  return;
1498 
1499  if (m_rWW8Export.IsInTable())
1500  return;
1501 
1502  // #i36867 In word the text in a table is rotated via the TC or NS_sprm::TTextFlow::val
1503  // This means you can only rotate all or none of the text adding NS_sprm::CFELayout::val
1504  // here corrupts the table, hence !m_rWW8Export.bIsInTable
1505 
1506  m_rWW8Export.InsUInt16( NS_sprm::CFELayout::val );
1507  m_rWW8Export.pO->push_back( sal_uInt8(0x06) ); //len 6
1508  m_rWW8Export.pO->push_back( sal_uInt8(0x01) );
1509 
1510  m_rWW8Export.InsUInt16( rRotate.IsFitToLine() ? 1 : 0 );
1511  static const sal_uInt8 aZeroArr[ 3 ] = { 0, 0, 0 };
1512  m_rWW8Export.pO->insert( m_rWW8Export.pO->end(), aZeroArr, aZeroArr+3);
1513 }
1514 
1516 {
1517  sal_uInt8 nVal;
1518  const FontEmphasisMark v = rEmphasisMark.GetEmphasisMark();
1519  if (v == FontEmphasisMark::NONE)
1520  nVal = 0;
1521  else if (v == (FontEmphasisMark::Accent | FontEmphasisMark::PosAbove))
1522  nVal = 2;
1523  else if (v == (FontEmphasisMark::Circle | FontEmphasisMark::PosAbove))
1524  nVal = 3;
1525  else if (v == (FontEmphasisMark::Dot | FontEmphasisMark::PosBelow))
1526  nVal = 4;
1527  else
1528  // case 1:
1529  nVal = 1;
1530 
1531  m_rWW8Export.InsUInt16( NS_sprm::CKcd::val );
1532  m_rWW8Export.pO->push_back( nVal );
1533 }
1534 
1543 bool WW8Export::TransBrush(const Color& rCol, WW8_SHD& rShd)
1544 {
1545  if( rCol.GetTransparency() )
1546  rShd = WW8_SHD(); // all zeros: transparent
1547  else
1548  {
1549  rShd.SetFore( 0);
1550  rShd.SetBack( msfilter::util::TransColToIco( rCol ) );
1551  rShd.SetStyle( 0 );
1552  }
1553  return !rCol.GetTransparency();
1554 }
1555 
1556 static sal_uInt32 SuitableBGColor(Color nIn)
1557 {
1558  if (nIn == COL_AUTO)
1559  return 0xFF000000;
1560  return wwUtility::RGBToBGR(nIn);
1561 }
1562 
1564 {
1565  m_rWW8Export.InsUInt16( NS_sprm::CIco::val );
1566 
1567  sal_uInt8 nColor = msfilter::util::TransColToIco( rColor.GetValue() );
1568  m_rWW8Export.pO->push_back( nColor );
1569 
1570  if (nColor)
1571  {
1572  m_rWW8Export.InsUInt16( NS_sprm::CCv::val );
1573  m_rWW8Export.InsUInt32( wwUtility::RGBToBGR( rColor.GetValue() ) );
1574  }
1575 }
1576 
1578 {
1579  WW8_SHD aSHD;
1580 
1581  WW8Export::TransBrush( rBrush.GetColor(), aSHD );
1582  // sprmCShd80
1583  m_rWW8Export.InsUInt16( NS_sprm::CShd80::val );
1584  m_rWW8Export.InsUInt16( aSHD.GetValue() );
1585 
1586  //Quite a few unknowns, some might be transparency or something
1587  //of that nature...
1588  m_rWW8Export.InsUInt16( NS_sprm::CShd::val );
1589  m_rWW8Export.pO->push_back( 10 );
1590  m_rWW8Export.InsUInt32( 0xFF000000 );
1591  m_rWW8Export.InsUInt32( SuitableBGColor( rBrush.GetColor() ) );
1592  m_rWW8Export.InsUInt16( 0x0000);
1593 }
1594 
1595 namespace sw { namespace util {
1596 
1598 {
1599  if (rINet.GetValue().isEmpty())
1600  return nullptr;
1601 
1602  const sal_uInt16 nId = rINet.GetINetFormatId();
1603  const OUString& rStr = rINet.GetINetFormat();
1604  if (rStr.isEmpty())
1605  {
1606  OSL_ENSURE( false, "WW8AttributeOutput::TextINetFormat(..) - missing unvisited character format at hyperlink attribute" );
1607  }
1608 
1609  return IsPoolUserFormat( nId )
1610  ? rDoc.FindCharFormatByName( rStr )
1612 }
1613 
1614 } }
1615 
1617 {
1618  const SwCharFormat* pFormat = GetSwCharFormat(rINet, m_rWW8Export.m_rDoc);
1619  if (!pFormat)
1620  return;
1621 
1622  m_rWW8Export.InsUInt16( NS_sprm::CIstd::val );
1623 
1624  m_rWW8Export.InsUInt16( m_rWW8Export.GetId( pFormat ) );
1625 }
1626 
1627 // #i43956# - add optional parameter <pLinkStr>
1628 // It's needed to write the hyperlink data for a certain cross-reference
1629 // - it contains the name of the link target, which is a bookmark.
1630 // add optional parameter <bIncludeEmptyPicLocation>
1631 // It is needed to write an empty picture location for page number field separators
1632 static void InsertSpecialChar( WW8Export& rWrt, sal_uInt8 c,
1633  OUString const * pLinkStr,
1634  bool bIncludeEmptyPicLocation = false )
1635 {
1636  ww::bytes aItems;
1637  rWrt.GetCurrentItems(aItems);
1638 
1639  if (c == 0x13)
1640  rWrt.m_pChpPlc->AppendFkpEntry(rWrt.Strm().Tell());
1641  else
1642  rWrt.m_pChpPlc->AppendFkpEntry(rWrt.Strm().Tell(), aItems.size(), aItems.data());
1643 
1644  rWrt.WriteChar(c);
1645 
1646  // store empty sprmCPicLocation for field separator
1647  if ( bIncludeEmptyPicLocation &&
1648  ( c == 0x13 || c == 0x14 || c == 0x15 ) )
1649  {
1651  SwWW8Writer::InsUInt32( aItems, 0x00000000 );
1652  }
1653 
1654  // #i43956# - write hyperlink data and attributes
1655  if ( c == 0x01 && pLinkStr)
1656  {
1657  // write hyperlink data to data stream
1658  SvStream& rStrm = *rWrt.pDataStrm;
1659  // position of hyperlink data
1660  const sal_uInt32 nLinkPosInDataStrm = rStrm.Tell();
1661  // write empty header
1662  const sal_uInt16 nEmptyHdrLen = 0x44;
1663  sal_uInt8 aEmptyHeader[ nEmptyHdrLen ] = { 0 };
1664  aEmptyHeader[ 4 ] = 0x44;
1665  rStrm.WriteBytes( aEmptyHeader, nEmptyHdrLen );
1666  // writer fixed header
1667  const sal_uInt16 nFixHdrLen = 0x19;
1668  sal_uInt8 const aFixHeader[ nFixHdrLen ] =
1669  {
1670  0x08, 0xD0, 0xC9, 0xEA, 0x79, 0xF9, 0xBA, 0xCE,
1671  0x11, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9,
1672  0x0B, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
1673  0x00,
1674  };
1675  rStrm.WriteBytes( aFixHeader, nFixHdrLen );
1676  // write reference string including length+1
1677  sal_uInt32 nStrLen( pLinkStr->getLength() + 1 );
1678  SwWW8Writer::WriteLong( rStrm, nStrLen );
1679  SwWW8Writer::WriteString16( rStrm, *pLinkStr, false );
1680  // write additional two NULL Bytes
1681  SwWW8Writer::WriteLong( rStrm, 0 );
1682  // write length of hyperlink data
1683  const sal_uInt32 nCurrPos = rStrm.Tell();
1684  rStrm.Seek( nLinkPosInDataStrm );
1685  rStrm.WriteUInt32(nCurrPos - nLinkPosInDataStrm);
1686  rStrm.Seek( nCurrPos );
1687 
1688  // write attributes of hyperlink character 0x01
1690  aItems.push_back( sal_uInt8(0x81) );
1692  SwWW8Writer::InsUInt32( aItems, nLinkPosInDataStrm );
1694  aItems.push_back( sal_uInt8(0x01) );
1695  }
1696 
1697  //Technically we should probably Remove all attribs
1698  //here for the 0x13, 0x14, 0x15, but our import
1699  //is slightly lacking
1700  //aItems.Remove(0, aItems.Count());
1701  // fSpec-Attribute true
1703  aItems.push_back( 1 );
1704 
1705  rWrt.m_pChpPlc->AppendFkpEntry(rWrt.Strm().Tell(), aItems.size(), aItems.data());
1706 }
1707 
1708 static OUString lcl_GetExpandedField(const SwField &rField)
1709 {
1710  //replace LF 0x0A with VT 0x0B
1711  return rField.ExpandField(true, nullptr).replace(0x0A, 0x0B);
1712 }
1713 
1715 {
1716  WW8_WrPlcField* pFieldP = nullptr;
1717  switch (m_nTextTyp)
1718  {
1719  case TXT_MAINTEXT:
1720  pFieldP = m_pFieldMain.get();
1721  break;
1722  case TXT_HDFT:
1723  pFieldP = m_pFieldHdFt.get();
1724  break;
1725  case TXT_FTN:
1726  pFieldP = m_pFieldFootnote.get();
1727  break;
1728  case TXT_EDN:
1729  pFieldP = m_pFieldEdn.get();
1730  break;
1731  case TXT_ATN:
1732  pFieldP = m_pFieldAtn.get();
1733  break;
1734  case TXT_TXTBOX:
1735  pFieldP = m_pFieldTextBxs.get();
1736  break;
1737  case TXT_HFTXTBOX:
1738  pFieldP = m_pFieldHFTextBxs.get();
1739  break;
1740  default:
1741  OSL_ENSURE( false, "what type of SubDoc is that?" );
1742  }
1743  return pFieldP;
1744 }
1745 
1746 void WW8Export::OutputField( const SwField* pField, ww::eField eFieldType,
1747  const OUString& rFieldCmd, FieldFlags nMode )
1748 {
1749  OUString sFieldCmd(rFieldCmd);
1750  switch (eFieldType)
1751  {
1752  // map fields that are not supported in WW8 as of Word 2003
1753  case ww::eBIBLIOGRAPHY:
1754  eFieldType = ww::eQUOTE;
1755  assert(rFieldCmd == FieldString(ww::eBIBLIOGRAPHY));
1756  sFieldCmd = FieldString(ww::eQUOTE);
1757  break;
1758  case ww::eCITATION:
1759  eFieldType = ww::eQUOTE;
1760  assert(rFieldCmd.trim().startsWith("CITATION"));
1761  sFieldCmd = rFieldCmd.replaceFirst(FieldString(ww::eCITATION),
1763  break;
1764  default:
1765  break;
1766  }
1767 
1768  assert(eFieldType <= 0x5F); // 95 is the highest documented one
1769 
1770  WW8_WrPlcField* pFieldP = CurrentFieldPlc();
1771 
1772  const bool bIncludeEmptyPicLocation = ( eFieldType == ww::ePAGE );
1773  if (FieldFlags::Start & nMode)
1774  {
1775  sal_uInt8 aField13[2] = { 0x13, 0x00 }; // will change
1776  //#i3958#, Needed to make this field work correctly in Word 2000
1777  if (eFieldType == ww::eSHAPE)
1778  aField13[0] |= 0x80;
1779  aField13[1] = static_cast< sal_uInt8 >(eFieldType); // add type
1780  pFieldP->Append( Fc2Cp( Strm().Tell() ), aField13 );
1781  InsertSpecialChar( *this, 0x13, nullptr, bIncludeEmptyPicLocation );
1782  }
1783  if (FieldFlags::CmdStart & nMode)
1784  {
1785  SwWW8Writer::WriteString16(Strm(), sFieldCmd, false);
1786  // #i43956# - write hyperlink character including
1787  // attributes and corresponding binary data for certain reference fields.
1788  bool bHandleBookmark = false;
1789 
1790  if (pField)
1791  {
1792  if (pField->GetTyp()->Which() == SwFieldIds::GetRef &&
1793  ( eFieldType == ww::ePAGEREF || eFieldType == ww::eREF ||
1794  eFieldType == ww::eNOTEREF || eFieldType == ww::eFOOTREF ))
1795  bHandleBookmark = true;
1796  }
1797 
1798  if ( bHandleBookmark )
1799  {
1800  // retrieve reference destination - the name of the bookmark
1801  OUString aLinkStr;
1802  const sal_uInt16 nSubType = pField->GetSubType();
1803  const SwGetRefField& rRField = *static_cast<const SwGetRefField*>(pField);
1804  if ( nSubType == REF_SETREFATTR ||
1805  nSubType == REF_BOOKMARK )
1806  {
1807  const OUString& aRefName(rRField.GetSetRefName());
1808  aLinkStr = GetBookmarkName( nSubType, &aRefName, 0 );
1809  }
1810  else if ( nSubType == REF_FOOTNOTE ||
1811  nSubType == REF_ENDNOTE )
1812  {
1813  aLinkStr = GetBookmarkName( nSubType, nullptr, rRField.GetSeqNo() );
1814  }
1815  else if ( nSubType == REF_SEQUENCEFLD )
1816  {
1817  aLinkStr = pField->GetPar2();
1818  }
1819  // insert hyperlink character including attributes and data.
1820  InsertSpecialChar( *this, 0x01, &aLinkStr );
1821  }
1822  }
1823  if (FieldFlags::CmdEnd & nMode)
1824  {
1825  static const sal_uInt8 aField14[2] = { 0x14, 0xff };
1826  pFieldP->Append( Fc2Cp( Strm().Tell() ), aField14 );
1827  pFieldP->ResultAdded();
1828  InsertSpecialChar( *this, 0x14, nullptr, bIncludeEmptyPicLocation );
1829  }
1830  if (FieldFlags::End & nMode)
1831  {
1832  OUString sOut;
1833  if( pField )
1834  sOut = lcl_GetExpandedField(*pField);
1835  else
1836  sOut = sFieldCmd;
1837  if( !sOut.isEmpty() )
1838  {
1839  SwWW8Writer::WriteString16(Strm(), sOut, false);
1840 
1841  if (pField)
1842  {
1843  if (pField->GetTyp()->Which() == SwFieldIds::Input &&
1844  eFieldType == ww::eFORMTEXT)
1845  {
1846  sal_uInt8 aArr[12];
1847  sal_uInt8 *pArr = aArr;
1848 
1850  Set_UInt32( pArr, 0x0 );
1851 
1853  Set_UInt8( pArr, 1 );
1854 
1856  Set_UInt8( pArr, 1 );
1857 
1858  m_pChpPlc->AppendFkpEntry( Strm().Tell(), static_cast< short >(pArr - aArr), aArr );
1859  }
1860  }
1861  }
1862  }
1863  if (!(FieldFlags::Close & nMode))
1864  return;
1865 
1866  sal_uInt8 aField15[2] = { 0x15, 0x80 };
1867 
1868  if (pField)
1869  {
1870  if (pField->GetTyp()->Which() == SwFieldIds::Input &&
1871  eFieldType == ww::eFORMTEXT)
1872  {
1873  sal_uInt16 nSubType = pField->GetSubType();
1874 
1875  if (nSubType == REF_SEQUENCEFLD)
1876  aField15[0] |= (0x4 << 5);
1877  }
1878  }
1879 
1880  pFieldP->Append( Fc2Cp( Strm().Tell() ), aField15 );
1881  InsertSpecialChar( *this, 0x15, nullptr, bIncludeEmptyPicLocation );
1882 }
1883 
1884 void WW8Export::StartCommentOutput(const OUString& rName)
1885 {
1886  const OUString sStr{ FieldString(ww::eQUOTE) + "[" + rName + "] " };
1887  OutputField(nullptr, ww::eQUOTE, sStr, FieldFlags::Start | FieldFlags::CmdStart);
1888 }
1889 
1890 void WW8Export::EndCommentOutput(const OUString& rName)
1891 {
1892  const OUString sStr{ " [" + rName + "] " };
1893  OutputField(nullptr, ww::eQUOTE, sStr, FieldFlags::CmdEnd | FieldFlags::End |
1895 }
1896 
1897 sal_uInt16 MSWordExportBase::GetId( const SwTOXType& rTOXType )
1898 {
1899  std::vector<const SwTOXType*>::iterator it
1900  = std::find( m_aTOXArr.begin(), m_aTOXArr.end(), &rTOXType );
1901  if ( it != m_aTOXArr.end() )
1902  {
1903  return it - m_aTOXArr.begin();
1904  }
1905  m_aTOXArr.push_back( &rTOXType );
1906  return m_aTOXArr.size() - 1;
1907 }
1908 
1909 // return values: 1 - no PageNum,
1910 // 2 - TabStop before PageNum,
1911 // 3 - Text before PageNum - rText hold the text
1912 // 4 - no Text and no TabStop before PageNum
1913 static int lcl_CheckForm( const SwForm& rForm, sal_uInt8 nLvl, OUString& rText )
1914 {
1915  int nRet = 4;
1916  rText.clear();
1917 
1918  // #i21237#
1919  SwFormTokens aPattern = rForm.GetPattern(nLvl);
1920  SwFormTokens::iterator aIt = aPattern.begin();
1921  FormTokenType eTType;
1922 
1923  // #i61362#
1924  if (! aPattern.empty())
1925  {
1926  bool bPgNumFnd = false;
1927 
1928  // #i21237#
1929  while( ++aIt != aPattern.end() && !bPgNumFnd )
1930  {
1931  eTType = aIt->eTokenType;
1932 
1933  switch( eTType )
1934  {
1935  case TOKEN_PAGE_NUMS:
1936  bPgNumFnd = true;
1937  break;
1938 
1939  case TOKEN_TAB_STOP:
1940  nRet = 2;
1941  break;
1942  case TOKEN_TEXT:
1943  {
1944  nRet = 3;
1945  sal_Int32 nCount = std::min<sal_Int32>(5, aIt->sText.getLength());
1946  rText = aIt->sText.copy(0, nCount); // #i21237#
1947  break;
1948  }
1949  case TOKEN_LINK_START:
1950  case TOKEN_LINK_END:
1951  break;
1952 
1953  default:
1954  nRet = 4;
1955  break;
1956  }
1957  }
1958 
1959  if( !bPgNumFnd )
1960  nRet = 1;
1961  }
1962 
1963  return nRet;
1964 }
1965 
1966 static bool lcl_IsHyperlinked(const SwForm& rForm, sal_uInt16 nTOXLvl)
1967 {
1968  bool bRes = false;
1969  for (sal_uInt16 nI = 1; nI < nTOXLvl; ++nI)
1970  {
1971  // #i21237#
1972  SwFormTokens aPattern = rForm.GetPattern(nI);
1973 
1974  if ( !aPattern.empty() )
1975  {
1976  SwFormTokens::iterator aIt = aPattern.begin();
1977 
1978  FormTokenType eTType;
1979 
1980  // #i21237#
1981  while ( ++aIt != aPattern.end() )
1982  {
1983  eTType = aIt->eTokenType;
1984  switch (eTType)
1985  {
1986  case TOKEN_LINK_START:
1987  case TOKEN_LINK_END:
1988  bRes = true;
1989  break;
1990  default:
1991  ;
1992  }
1993  }
1994  }
1995  }
1996  return bRes;
1997 }
1998 
2000 {
2001  if(GetExport().GetExportFormat() == MSWordExportBase::ExportFormat::RTF) // Not implemented for RTF
2002  return;
2003 
2004  const SwpHints* pTextAttrs = rNode.GetpSwpHints();
2005  if (!pTextAttrs)
2006  return;
2007 
2008  for( size_t i = 0; i < pTextAttrs->Count(); ++i )
2009  {
2010  const SwTextAttr* pHt = pTextAttrs->Get(i);
2011  if (pHt->GetAttr().Which() == RES_TXTATR_FIELD)
2012  {
2013  const SwFormatField& rField = static_cast<const SwFormatField&>(pHt->GetAttr());
2014  const SwField* pField = rField.GetField();
2015  // Need to have bookmarks only for sequence fields
2016  if (pField && pField->GetTyp()->Which() == SwFieldIds::SetExp && pField->GetSubType() == nsSwGetSetExpType::GSE_SEQ)
2017  {
2018  const sal_uInt16 nSeqFieldNumber = static_cast<const SwSetExpField*>(pField)->GetSeqNumber();
2019  const OUString sObjectName = static_cast<const SwSetExpFieldType*>(pField->GetTyp())->GetName();
2020  const SwFieldTypes* pFieldTypes = GetExport().m_rDoc.getIDocumentFieldsAccess().GetFieldTypes();
2021  bool bHaveFullBkm = false;
2022  bool bHaveLabelAndNumberBkm = false;
2023  bool bHaveCaptionOnlyBkm = false;
2024  bool bHaveNumberOnlyBkm = false;
2025  bool bRunSplittedAtSep = false;
2026  for( auto const & pFieldType : *pFieldTypes )
2027  {
2028  if( SwFieldIds::GetRef == pFieldType->Which() )
2029  {
2030  SwIterator<SwFormatField,SwFieldType> aIter( *pFieldType );
2031  for( SwFormatField* pFormatField = aIter.First(); pFormatField; pFormatField = aIter.Next() )
2032  {
2033  SwGetRefField* pRefField = static_cast<SwGetRefField*>(pFormatField->GetField());
2034  // If we have a reference to the current sequence field
2035  if(pRefField->GetSeqNo() == nSeqFieldNumber && pRefField->GetSetRefName() == sObjectName)
2036  {
2037  // Need to create a separate run for separator character
2038  SwWW8AttrIter aLocalAttrIter( GetExport(), rNode ); // We need a local iterator having the right number of runs
2039  const OUString& aText = rNode.GetText();
2040  const sal_Int32 nCategoryStart = aText.indexOf(pRefField->GetSetRefName());
2041  const sal_Int32 nPosBeforeSeparator = std::max(nCategoryStart, pHt->GetStart());
2042  bool bCategoryFirst = nCategoryStart < pHt->GetStart();
2043  sal_Int32 nSeparatorPos = 0;
2044  if (bCategoryFirst)
2045  {
2046  nSeparatorPos = aLocalAttrIter.WhereNext();
2047  while (nSeparatorPos <= nPosBeforeSeparator)
2048  {
2049  aLocalAttrIter.NextPos();
2050  nSeparatorPos = aLocalAttrIter.WhereNext();
2051  }
2052  }
2053  else
2054  {
2055  nSeparatorPos = nCategoryStart + pRefField->GetSetRefName().getLength();
2056  }
2057  sal_Int32 nRefTextPos = 0;
2058  if(nSeparatorPos < aText.getLength())
2059  {
2060  nRefTextPos = SwGetExpField::GetReferenceTextPos(pHt->GetFormatField(), GetExport().m_rDoc, nSeparatorPos);
2061  if(nRefTextPos != nSeparatorPos)
2062  {
2063  if(!bRunSplittedAtSep)
2064  {
2065  if(!bCategoryFirst)
2066  rAttrIter.SplitRun(nSeparatorPos);
2067  rAttrIter.SplitRun(nRefTextPos);
2068  bRunSplittedAtSep = true;
2069  }
2070  if(!bCategoryFirst)
2071  aLocalAttrIter.SplitRun(nSeparatorPos);
2072  aLocalAttrIter.SplitRun(nRefTextPos);
2073  }
2074  else if (bCategoryFirst)
2075  {
2076  if(!bRunSplittedAtSep)
2077  {
2078  rAttrIter.SplitRun(nSeparatorPos);
2079  bRunSplittedAtSep = true;
2080  }
2081  aLocalAttrIter.SplitRun(nSeparatorPos);
2082  }
2083  }
2084  // Generate bookmarks on the right position
2085  OUString sName("Ref_" + pRefField->GetSetRefName() + OUString::number(pRefField->GetSeqNo()));
2086  switch (pRefField->GetFormat())
2087  {
2088  case REF_PAGE:
2089  case REF_PAGE_PGDESC:
2090  case REF_CONTENT:
2091  case REF_UPDOWN:
2092  if(!bHaveFullBkm)
2093  {
2094  sal_Int32 nLastAttrStart = 0;
2095  sal_Int32 nActAttr = aLocalAttrIter.WhereNext();
2096  while (nActAttr < rNode.GetText().getLength())
2097  {
2098  nLastAttrStart = nActAttr;
2099  aLocalAttrIter.NextPos();
2100  nActAttr = aLocalAttrIter.WhereNext();
2101  }
2102  WriteBookmarkInActParagraph( sName + "_full", std::min(nCategoryStart, pHt->GetStart()), nLastAttrStart );
2103  bHaveFullBkm = true;
2104  }
2105  break;
2106  case REF_ONLYNUMBER:
2107  {
2108  if(!bHaveLabelAndNumberBkm)
2109  {
2110  sName += "_label_and_number";
2111  if(bCategoryFirst)
2112  WriteBookmarkInActParagraph( sName, std::min(nCategoryStart, pHt->GetStart()), std::max(nCategoryStart, pHt->GetStart()) );
2113  else
2114  {
2115  // Find the last run which contains category text
2116  SwWW8AttrIter aLocalAttrIter2( GetExport(), rNode );
2117  sal_Int32 nCatLastRun = 0;
2118  sal_Int32 nNextAttr = aLocalAttrIter2.WhereNext();
2119  while (nNextAttr < nSeparatorPos)
2120  {
2121  nCatLastRun = nNextAttr;
2122  aLocalAttrIter2.NextPos();
2123  nNextAttr = aLocalAttrIter2.WhereNext();
2124  }
2125  WriteBookmarkInActParagraph( sName, pHt->GetStart(), nCatLastRun );
2126  }
2127  bHaveLabelAndNumberBkm = true;
2128  }
2129  break;
2130  }
2131  case REF_ONLYCAPTION:
2132  {
2133  if(!bHaveCaptionOnlyBkm)
2134  {
2135  // Find last run
2136  sal_Int32 nLastAttrStart = 0;
2137  sal_Int32 nActAttr = aLocalAttrIter.WhereNext();
2138  while (nActAttr < rNode.GetText().getLength())
2139  {
2140  nLastAttrStart = nActAttr;
2141  aLocalAttrIter.NextPos();
2142  nActAttr = aLocalAttrIter.WhereNext();
2143  }
2144  WriteBookmarkInActParagraph( sName + "_caption_only", nRefTextPos, nLastAttrStart );
2145  bHaveCaptionOnlyBkm = true;
2146  }
2147  break;
2148  }
2149  case REF_ONLYSEQNO:
2150  {
2151  if(!bHaveNumberOnlyBkm)
2152  {
2153  WriteBookmarkInActParagraph( sName + "_number_only", pHt->GetStart(), pHt->GetStart() );
2154  bHaveNumberOnlyBkm = true;
2155  }
2156  break;
2157  }
2158  }
2159  }
2160  }
2161  }
2162  }
2163  return;
2164  }
2165  }
2166  }
2167 }
2168 
2170 {
2171  if ( const SwTOXBase* pTOX = rSect.GetTOXBase() )
2172  {
2173  static const char sEntryEnd[] = "\" ";
2174 
2175  ww::eField eCode = ww::eTOC;
2176  OUString sStr = pTOX ->GetMSTOCExpression();
2177  if ( sStr.isEmpty() )
2178  {
2179  switch (pTOX->GetType())
2180  {
2181  case TOX_INDEX:
2182  eCode = ww::eINDEX;
2183  sStr = FieldString(eCode);
2184 
2185  {
2186  const SwFormatCol& rCol = rSect.GetFormat()->GetFormatAttr( RES_COL );
2187  const SwColumns& rColumns = rCol.GetColumns();
2188  sal_Int32 nCol = rColumns.size();
2189 
2190  if ( 0 < nCol )
2191  {
2192  // Add a continuous section break
2193  if( GetExport().AddSectionBreaksForTOX() )
2194  {
2195  SwSection *pParent = rSect.GetParent();
2196  WW8_SepInfo rInfo(&GetExport().m_rDoc.GetPageDesc(0),
2197  pParent ? pParent->GetFormat() : nullptr, 0/*nRstLnNum*/);
2198  GetExport( ).AttrOutput().SectionBreak( msword::PageBreak, false, &rInfo );
2199  }
2200 
2201  sStr += "\\c \"" + OUString::number( nCol ) + "\"";
2202  }
2203  }
2204 
2205  if (pTOX->GetTOXForm().IsCommaSeparated())
2206  sStr += "\\r ";
2207 
2208  if (SwTOIOptions::AlphaDelimiter & pTOX->GetOptions())
2209  sStr += "\\h \"A\" ";
2210 
2211  if(SwTOXElement::IndexEntryType & pTOX->GetCreateType())
2212  {
2213  sStr += "\\f ";
2214  const OUString& sName = pTOX->GetEntryTypeName();
2215  if(!sName.isEmpty())
2216  {
2217  sStr += sName + sEntryEnd;
2218  }
2219  }
2220 
2221  if (!pTOX->GetTOXForm().IsCommaSeparated())
2222  {
2223  // In case of Run-in style no separators are added.
2224  OUString aFillText;
2225  for (sal_uInt8 n = 1; n <= 3; ++n)
2226  {
2227  OUString aText;
2228  int nRet = ::lcl_CheckForm(pTOX->GetTOXForm(), n, aText);
2229 
2230  if( 3 == nRet )
2231  aFillText = aText;
2232  else if ((4 == nRet) || (2 == nRet))
2233  aFillText = "\t";
2234  else
2235  aFillText.clear();
2236  }
2237  sStr += "\\e \"" + aFillText + sEntryEnd;
2238  }
2239  break;
2240 
2241  case TOX_ILLUSTRATIONS:
2242  case TOX_OBJECTS:
2243  case TOX_TABLES:
2244  if (!pTOX->IsFromObjectNames())
2245  {
2246  sStr = FieldString(eCode) + "\\c ";
2247  const OUString& seqName = pTOX->GetSequenceName();
2248  if(!seqName.isEmpty())
2249  {
2250  sStr += "\"" + seqName + sEntryEnd;
2251  }
2252  OUString aText;
2253  int nRet = ::lcl_CheckForm( pTOX->GetTOXForm(), 1, aText );
2254  if (1 == nRet)
2255  sStr += "\\n ";
2256  else if( 3 == nRet || 4 == nRet )
2257  {
2258  sStr += "\\p \"" + aText + sEntryEnd;
2259  }
2260  }
2261  break;
2262 
2263  case TOX_AUTHORITIES:
2264  eCode = ww::eBIBLIOGRAPHY;
2265  sStr = FieldString(eCode);
2266  break;
2267  // case TOX_USER:
2268  // case TOX_CONTENT:
2269  default:
2270  {
2271  sStr = FieldString(eCode);
2272 
2273  OUString sTOption;
2274  sal_uInt16 n, nTOXLvl = pTOX->GetLevel();
2275  if( !nTOXLvl )
2276  ++nTOXLvl;
2277 
2278  if(SwTOXElement::TableLeader & pTOX->GetCreateType())
2279  {
2280  sStr +="\\z " ;
2281  GetExport( ).m_bHideTabLeaderAndPageNumbers = true ;
2282  }
2283  if(SwTOXElement::TableInToc & pTOX->GetCreateType())
2284  {
2285  sStr +="\\w " ;
2286  GetExport( ).m_bTabInTOC = true ;
2287  }
2288  if(SwTOXElement::Newline & pTOX->GetCreateType())
2289  {
2290  sStr +="\\x " ;
2291  }
2292  if( SwTOXElement::Mark & pTOX->GetCreateType() )
2293  {
2294  sStr += "\\f ";
2295 
2296  if( TOX_USER == pTOX->GetType() )
2297  {
2298  sStr += "\""
2299  + OUStringChar(static_cast<char>( 'A' + GetExport( ).GetId( *pTOX->GetTOXType() ) ))
2300  + sEntryEnd;
2301  }
2302  }
2303  if(SwTOXElement::Bookmark & pTOX->GetCreateType())
2304  {
2305  sStr += "\\b \"" + pTOX->GetBookmarkName() + sEntryEnd;
2306  }
2307 
2308  if( SwTOXElement::OutlineLevel & pTOX->GetCreateType() )
2309  {
2310  // Take the TOC value of the max level to evaluate to as
2311  // the starting point for the \o flag, but reduce it to the
2312  // value of the highest outline level filled by a *standard*
2313  // Heading 1 - 9 style because \o "Builds a table of
2314  // contents from paragraphs formatted with built-in heading
2315  // styles". And afterward fill in any outline styles left
2316  // uncovered by that range to the \t flag
2317 
2318  // i.e. for
2319  // Heading 1
2320  // Heading 2
2321  // custom-style
2322  // Heading 4
2323  // output
2324  // \o 1-2 \tcustom-style,3,Heading 3,4
2325 
2326  // Search over all the outline styles used and figure out
2327  // what is the minimum outline level (if any) filled by a
2328  // non-standard style for that level, i.e. ignore headline
2329  // styles 1-9 and find the lowest valid outline level
2330  sal_uInt8 nPosOfLowestNonStandardLvl = MAXLEVEL;
2331  const SwTextFormatColls& rColls = *GetExport().m_rDoc.GetTextFormatColls();
2332  for( n = rColls.size(); n; )
2333  {
2334  const SwTextFormatColl* pColl = rColls[ --n ];
2335  sal_uInt16 nPoolId = pColl->GetPoolFormatId();
2336  if (
2337  //Is a Non-Standard Outline Style
2338  (RES_POOLCOLL_HEADLINE1 > nPoolId || RES_POOLCOLL_HEADLINE9 < nPoolId) &&
2339  //Has a valid outline level
2341  // Is less than the lowest known non-standard level
2342  (pColl->GetAssignedOutlineStyleLevel() < nPosOfLowestNonStandardLvl)
2343  )
2344  {
2345  nPosOfLowestNonStandardLvl = ::sal::static_int_cast<sal_uInt8>(pColl->GetAssignedOutlineStyleLevel());
2346  }
2347  }
2348 
2349  sal_uInt8 nMaxMSAutoEvaluate = nPosOfLowestNonStandardLvl < nTOXLvl ? nPosOfLowestNonStandardLvl : static_cast<sal_uInt8>(nTOXLvl);
2350 
2351  //output \o 1-X where X is the highest normal outline style to be included in the toc
2352  if ( nMaxMSAutoEvaluate )
2353  {
2354  if (nMaxMSAutoEvaluate > WW8ListManager::nMaxLevel)
2355  nMaxMSAutoEvaluate = WW8ListManager::nMaxLevel;
2356 
2357  sStr += "\\o \"1-" + OUString::number(nMaxMSAutoEvaluate) + sEntryEnd;
2358  }
2359 
2360  //collect up any other styles in the writer TOC which will
2361  //not already appear in the MS TOC and place then into the
2362  //\t option
2363  if( nMaxMSAutoEvaluate < nTOXLvl )
2364  {
2365  // collect this templates into the \t option
2366  for( n = rColls.size(); n;)
2367  {
2368  const SwTextFormatColl* pColl = rColls[ --n ];
2370  continue;
2371  sal_uInt8 nTestLvl = ::sal::static_int_cast<sal_uInt8>(pColl->GetAssignedOutlineStyleLevel());
2372  if (nTestLvl < nTOXLvl && nTestLvl >= nMaxMSAutoEvaluate)
2373  {
2374  if (!sTOption.isEmpty())
2375  sTOption += ",";
2376  sTOption += pColl->GetName() + "," + OUString::number( nTestLvl + 1 );
2377  }
2378  }
2379  }
2380  }
2381 
2382  if( SwTOXElement::ParagraphOutlineLevel & pTOX->GetCreateType() )
2383  {
2384  sStr +="\\u " ;
2385  }
2386 
2387  if( SwTOXElement::Template & pTOX->GetCreateType() )
2388  {
2389  // #i99641# - Consider additional styles regardless of TOX-outlinelevel
2390  for( n = 0; n < MAXLEVEL; ++n )
2391  {
2392  const OUString& rStyles = pTOX->GetStyleNames( n );
2393  if( !rStyles.isEmpty() )
2394  {
2395  sal_Int32 nPos = 0;
2396  const OUString sLvl{ "," + OUString::number( n + 1 ) };
2397  do {
2398  const OUString sStyle( rStyles.getToken( 0, TOX_STYLE_DELIMITER, nPos ));
2399  if( !sStyle.isEmpty() )
2400  {
2401  SwTextFormatColl* pColl = GetExport().m_rDoc.FindTextFormatCollByName(sStyle);
2402  if (pColl)
2403  {
2404  if (!pColl->IsAssignedToListLevelOfOutlineStyle() || pColl->GetAssignedOutlineStyleLevel() < nTOXLvl)
2405  {
2406  if( !sTOption.isEmpty() )
2407  sTOption += ",";
2408  sTOption += sStyle + sLvl;
2409  }
2410  }
2411  }
2412  } while( -1 != nPos );
2413  }
2414  }
2415  }
2416 
2417  // No 'else' branch; why the below snippet is a block I have no idea.
2418  {
2419  OUString aFillText;
2420  sal_uInt8 nNoPgStt = MAXLEVEL, nNoPgEnd = MAXLEVEL;
2421  bool bFirstFillText = true, bOnlyText = true;
2422  for( n = 0; n < nTOXLvl; ++n )
2423  {
2424  OUString aText;
2425  int nRet = ::lcl_CheckForm( pTOX->GetTOXForm(),
2426  static_cast< sal_uInt8 >(n+1), aText );
2427  if( 1 == nRet )
2428  {
2429  bOnlyText = false;
2430  if( MAXLEVEL == nNoPgStt )
2431  nNoPgStt = static_cast< sal_uInt8 >(n+1);
2432  }
2433  else
2434  {
2435  if( MAXLEVEL != nNoPgStt &&
2436  MAXLEVEL == nNoPgEnd )
2437  nNoPgEnd = sal_uInt8(n);
2438 
2439  bOnlyText = bOnlyText && 3 == nRet;
2440  if( 3 == nRet || 4 == nRet )
2441  {
2442  if( bFirstFillText )
2443  aFillText = aText;
2444  else if( aFillText != aText )
2445  aFillText.clear();
2446  bFirstFillText = false;
2447  }
2448  }
2449  }
2450  if( MAXLEVEL != nNoPgStt )
2451  {
2452  if (WW8ListManager::nMaxLevel < nNoPgEnd)
2453  nNoPgEnd = WW8ListManager::nMaxLevel;
2454  sStr += "\\n "
2455  + OUString::number( nNoPgStt )
2456  + "-"
2457  + OUString::number( nNoPgEnd )
2458  + " ";
2459  }
2460  if( bOnlyText )
2461  {
2462  sStr += "\\p \"" + aFillText + sEntryEnd;
2463  }
2464  }
2465 
2466  if( !sTOption.isEmpty() )
2467  {
2468  sStr += "\\t \"" + sTOption + sEntryEnd;
2469  }
2470 
2471  if (lcl_IsHyperlinked(pTOX->GetTOXForm(), nTOXLvl))
2472  sStr += "\\h";
2473  break;
2474  }
2475  }
2476  }
2477 
2478  if (!sStr.isEmpty())
2479  {
2480  GetExport( ).m_bInWriteTOX = true;
2481  if (GetExport().GetExportFormat() == MSWordExportBase::ExportFormat::RTF)
2482  { // tdf#129574: required for RTF; doesn't work with DOCX
2483  StartRun(nullptr, -42, true);
2484  }
2485  GetExport( ).OutputField( nullptr, eCode, sStr, FieldFlags::Start | FieldFlags::CmdStart |
2487  if (GetExport().GetExportFormat() == MSWordExportBase::ExportFormat::RTF)
2488  {
2489  EndRun(nullptr, -42, true);
2490  }
2491  }
2492  }
2493 
2494  GetExport( ).m_bStartTOX = false;
2495 }
2496 
2497 void AttributeOutputBase::EndTOX( const SwSection& rSect,bool bCareEnd )
2498 {
2499  const SwTOXBase* pTOX = rSect.GetTOXBase();
2500  if ( pTOX )
2501  {
2502  ww::eField eCode = TOX_INDEX == pTOX->GetType() ? ww::eINDEX : ww::eTOC;
2503  GetExport( ).OutputField( nullptr, eCode, OUString(), FieldFlags::Close );
2504 
2505  if ( pTOX->GetType() == TOX_INDEX && GetExport().AddSectionBreaksForTOX() )
2506  {
2507  const SwFormatCol& rCol = rSect.GetFormat()->GetFormatAttr( RES_COL );
2508  const SwColumns& rColumns = rCol.GetColumns();
2509  sal_Int32 nCol = rColumns.size();
2510 
2511  if ( 0 < nCol )
2512  {
2513  WW8_SepInfo rInfo( &GetExport().m_rDoc.GetPageDesc( 0 ), rSect.GetFormat(), 0/*nRstLnNum*/ );
2514  GetExport( ).AttrOutput().SectionBreak( msword::PageBreak, false, &rInfo );
2515  }
2516  }
2517  }
2518  GetExport( ).m_bInWriteTOX = false;
2519  GetExport( ).m_bHideTabLeaderAndPageNumbers = false;
2520  if (bCareEnd)
2521  OnTOXEnding();
2522 }
2523 
2524 bool MSWordExportBase::GetNumberFormat(const SwField& rField, OUString& rStr)
2525 {
2526  // Returns a date or time format string by using the US NfKeywordTable
2527  bool bHasFormat = false;
2529  sal_uInt32 nFormatIdx = rField.GetFormat();
2530  const SvNumberformat* pNumFormat = pNFormatr->GetEntry( nFormatIdx );
2531  if( pNumFormat )
2532  {
2533  LanguageType nLng = rField.GetLanguage();
2534  LocaleDataWrapper aLocDat(pNFormatr->GetComponentContext(),
2535  LanguageTag(nLng));
2536 
2537  OUString sFormat(pNumFormat->GetMappedFormatstring(GetNfKeywordTable(),
2538  aLocDat));
2539 
2540  if (!sFormat.isEmpty())
2541  {
2542  sw::ms::SwapQuotesInField(sFormat);
2543 
2544  rStr = "\\@\"" + sFormat + "\" " ;
2545  bHasFormat = true;
2546  }
2547  }
2548  return bHasFormat;
2549 }
2550 
2551 void AttributeOutputBase::GetNumberPara( OUString& rStr, const SwField& rField )
2552 {
2553  switch(rField.GetFormat())
2554  {
2557  rStr += "\\* ALPHABETIC ";
2558  break;
2561  rStr += "\\* alphabetic ";
2562  break;
2563  case SVX_NUM_ROMAN_UPPER:
2564  rStr += "\\* ROMAN ";
2565  break;
2566  case SVX_NUM_ROMAN_LOWER:
2567  rStr += "\\* roman ";
2568  break;
2569  default:
2570  OSL_ENSURE(rField.GetFormat() == SVX_NUM_ARABIC,
2571  "Unknown numbering type exported as default of Arabic");
2572  [[fallthrough]];
2573  case SVX_NUM_ARABIC:
2574  rStr += "\\* ARABIC ";
2575  break;
2576  case SVX_NUM_PAGEDESC:
2577  //Nothing, use word's default
2578  break;
2579  }
2580 }
2581 
2583 {
2584  sal_uInt8 aArr[ 3 ];
2585  sal_uInt8* pArr = aArr;
2586 
2587  // sprmCFSpec true
2589  Set_UInt8( pArr, 1 );
2590 
2591  m_pChpPlc->AppendFkpEntry( Strm().Tell() );
2592  WriteChar( 0x05 ); // Annotation reference
2593 
2594  if( pOut )
2595  pOut->insert( pOut->end(), aArr, pArr );
2596  else
2597  m_pChpPlc->AppendFkpEntry( Strm().Tell(), static_cast< short >(pArr - aArr), aArr );
2598 }
2599 
2600 OUString FieldString(ww::eField eIndex)
2601 {
2602  if (const char *pField = ww::GetEnglishFieldName(eIndex))
2603  return " " + OUString::createFromAscii(pField) + " ";
2604  return " ";
2605 }
2606 
2608 {
2609  //replace LF 0x0A with VT 0x0B
2610  const OUString sExpand(rField.GetPar2().replace(0x0A, 0x0B));
2611 
2612  m_rWW8Export.m_pChpPlc->AppendFkpEntry(m_rWW8Export.Strm().Tell());
2613  SwWW8Writer::WriteString16(m_rWW8Export.Strm(), sExpand, false);
2614  static sal_uInt8 aArr[] =
2615  {
2616  0x3C, 0x08, 0x1
2617  };
2618  m_rWW8Export.m_pChpPlc->AppendFkpEntry(m_rWW8Export.Strm().Tell(), sizeof(aArr), aArr);
2619 }
2620 
2621 void WW8AttributeOutput::SetField( const SwField& rField, ww::eField eType, const OUString& rCmd )
2622 {
2623  const SwSetExpField* pSet = static_cast<const SwSetExpField*>(&rField);
2624  const OUString &rVar = pSet->GetPar2();
2625 
2626  sal_uLong nFrom = m_rWW8Export.Fc2Cp(m_rWW8Export.Strm().Tell());
2627 
2628  GetExport().OutputField(&rField, eType, rCmd, FieldFlags::Start |
2630 
2631  /*
2632  Is there a bookmark at the start position of this field, if so
2633  move it to the 0x14 of the result of the field. This is what word
2634  does. MoveFieldMarks moves any bookmarks at this position to
2635  the beginning of the field result, and marks the bookmark as a
2636  fieldbookmark which is to be ended before the field end mark
2637  instead of after it like a normal bookmark.
2638  */
2639  m_rWW8Export.MoveFieldMarks(nFrom,m_rWW8Export.Fc2Cp(m_rWW8Export.Strm().Tell()));
2640 
2641  if (!rVar.isEmpty())
2642  {
2643  SwWW8Writer::WriteString16(m_rWW8Export.Strm(), rVar, false);
2644  }
2645  GetExport().OutputField(&rField, eType, rCmd, FieldFlags::Close);
2646 }
2647 
2649 {
2650  const SwPostItField *pPField = static_cast<const SwPostItField*>(pField);
2651  m_rWW8Export.m_pAtn->Append( m_rWW8Export.Fc2Cp( m_rWW8Export.Strm().Tell() ), pPField );
2652  m_rWW8Export.WritePostItBegin( m_rWW8Export.pO.get() );
2653 }
2654 
2656 {
2657  const SwDropDownField& rField2 = *static_cast<const SwDropDownField*>(pField);
2658  uno::Sequence<OUString> aItems =
2659  rField2.GetItemSequence();
2660  GetExport().DoComboBox(rField2.GetName(),
2661  rField2.GetHelp(),
2662  rField2.GetToolTip(),
2663  rField2.GetSelectedItem(), aItems);
2664  return false;
2665 }
2666 
2668 {
2669  return true; // expand to text?
2670 }
2671 
2672 void WW8AttributeOutput::RefField( const SwField &rField, const OUString &rRef)
2673 {
2674  const OUString sStr{ FieldString( ww::eREF ) + "\"" + rRef + "\" " };
2675  m_rWW8Export.OutputField( &rField, ww::eREF, sStr, FieldFlags::Start |
2677  const OUString sVar = lcl_GetExpandedField( rField );
2678  if ( !sVar.isEmpty() )
2679  {
2680  SwWW8Writer::WriteString16( m_rWW8Export.Strm(), sVar, false );
2681  }
2682  m_rWW8Export.OutputField( &rField, ww::eREF, sStr, FieldFlags::Close );
2683 }
2684 
2686 {
2687  SwWW8Writer::WriteString16( m_rWW8Export.Strm(), lcl_GetExpandedField( *pField ), false );
2688 }
2689 
2690 namespace
2691 {
2692 // Escapes a token string for storing in Word formats. Its import counterpart
2693 // is lcl_ExtractToken in writerfilter/source/dmapper/DomainMapper_Impl.cxx
2694 OUString EscapeToken(const OUString& rCommand)
2695 {
2696  bool bWasEscaped = false;
2697 
2698  const int nBufferLen = rCommand.getLength()*1.5;
2699  OUStringBuffer sResult(nBufferLen);
2700  sResult.append('"'); // opening quote
2701  for (sal_Int32 i = 0; i < rCommand.getLength(); ++i)
2702  {
2703  sal_Unicode ch = rCommand[i];
2704  switch (ch)
2705  {
2706  case '\\':
2707  case '"':
2708  // Backslashes and doublequotes must be escaped
2709  bWasEscaped = true;
2710  sResult.append('\\');
2711  break;
2712  case ' ':
2713  // Spaces require quotation
2714  bWasEscaped = true;
2715  break;
2716  }
2717  sResult.append(ch);
2718  }
2719 
2720  if (bWasEscaped)
2721  {
2722  sResult.append('"'); // closing quote
2723  return sResult.makeStringAndClear();
2724  }
2725  // No escapement/quotation was required
2726  return rCommand;
2727 }
2728 }
2729 
2731 {
2732  const SwField* pField = rField.GetField();
2733  bool bWriteExpand = false;
2734  const sal_uInt16 nSubType = pField->GetSubType();
2735 
2736  switch (pField->GetTyp()->Which())
2737  {
2738  case SwFieldIds::GetExp:
2739  if (nSubType == nsSwGetSetExpType::GSE_STRING)
2740  {
2741  const SwGetExpField *pGet = static_cast<const SwGetExpField*>(pField);
2742  RefField( *pGet, pGet->GetFormula() );
2743  }
2744  else
2745  bWriteExpand = true;
2746  break;
2747  case SwFieldIds::SetExp:
2748  if (nsSwGetSetExpType::GSE_SEQ == nSubType)
2749  {
2750  OUString sStr;
2751  if (GetExport().FieldsQuoted())
2752  sStr = FieldString(ww::eSEQ) + pField->GetTyp()->GetName() + " ";
2753  else
2754  sStr = FieldString(ww::eSEQ) + "\"" + pField->GetTyp()->GetName() +"\" ";
2755  GetNumberPara( sStr, *pField );
2756  GetExport().OutputField(pField, ww::eSEQ, sStr);
2757  }
2758  else if (nSubType & nsSwGetSetExpType::GSE_STRING)
2759  {
2760  bool bShowAsWell = false;
2761  ww::eField eFieldNo;
2762  const SwSetExpField *pSet = static_cast<const SwSetExpField*>(pField);
2763  const OUString sVar = pSet->GetPar2();
2764  OUString sStr;
2765  if (pSet->GetInputFlag())
2766  {
2767  sStr = FieldString(ww::eASK) + "\""
2768  + pSet->GetPar1() + "\" "
2769  + pSet->GetPromptText() + " \\d "
2770  + sVar;
2771  eFieldNo = ww::eASK;
2772  }
2773  else
2774  {
2775  sStr = FieldString(ww::eSET)
2776  + pSet->GetPar1() + " \""
2777  + sVar + "\" ";
2778  eFieldNo = ww::eSET;
2779  bShowAsWell = (nSubType & nsSwExtendedSubType::SUB_INVISIBLE) == 0;
2780  }
2781 
2782  SetField( *pField, eFieldNo, sStr );
2783 
2784  if (bShowAsWell)
2785  RefField( *pSet, pSet->GetPar1() );
2786  }
2787  else
2788  bWriteExpand = true;
2789  break;
2791  {
2792  OUString sStr = FieldString(ww::ePAGE);
2793  GetNumberPara(sStr, *pField);
2794  GetExport().OutputField(pField, ww::ePAGE, sStr);
2795  }
2796  break;
2797  case SwFieldIds::Filename:
2798  {
2799  OUString sStr = FieldString(ww::eFILENAME);
2800  if (pField->GetFormat() == FF_PATHNAME)
2801  sStr += "\\p ";
2802  GetExport().OutputField(pField, ww::eFILENAME, sStr);
2803  }
2804  break;
2805  case SwFieldIds::Database:
2806  {
2807  OUString sStr = FieldString(ww::eMERGEFIELD)
2808  + EscapeToken(static_cast<SwDBFieldType *>(pField->GetTyp())->GetColumnName()) + " ";
2809  GetExport().OutputField(pField, ww::eMERGEFIELD, sStr);
2810  }
2811  break;
2813  {
2814  SwDBData aData = GetExport().m_rDoc.GetDBData();
2815  const OUString sStr = FieldString(ww::eDATABASE)
2816  + aData.sDataSource
2817  + OUStringChar(DB_DELIM)
2818  + aData.sCommand;
2819  GetExport().OutputField(pField, ww::eDATABASE, sStr);
2820  }
2821  break;
2822  case SwFieldIds::Author:
2823  {
2824  ww::eField eField =
2826  GetExport().OutputField(pField, eField, FieldString(eField));
2827  }
2828  break;
2830  GetExport().OutputField(pField, ww::eTEMPLATE, FieldString(ww::eTEMPLATE));
2831  break;
2832  case SwFieldIds::DocInfo: // Last printed, last edited,...
2833  if( DI_SUB_FIXED & nSubType )
2834  bWriteExpand = true;
2835  else
2836  {
2837  OUString sStr;
2839  switch (0xff & nSubType)
2840  {
2841  case DI_TITLE:
2842  eField = ww::eTITLE;
2843  break;
2844  case DI_SUBJECT:
2845  eField = ww::eSUBJECT;
2846  break;
2847  case DI_KEYS:
2848  eField = ww::eKEYWORDS;
2849  break;
2850  case DI_COMMENT:
2851  eField = ww::eCOMMENTS;
2852  break;
2853  case DI_DOCNO:
2854  eField = ww::eREVNUM;
2855  break;
2856  case DI_CREATE:
2857  if (DI_SUB_AUTHOR == (nSubType & DI_SUB_MASK))
2858  eField = ww::eAUTHOR;
2859  else if (GetExport().GetNumberFormat(*pField, sStr))
2860  eField = ww::eCREATEDATE;
2861  break;
2862 
2863  case DI_CHANGE:
2864  if (DI_SUB_AUTHOR == (nSubType & DI_SUB_MASK))
2865  eField = ww::eLASTSAVEDBY;
2866  else if (GetExport().GetNumberFormat(*pField, sStr))
2867  eField = ww::eSAVEDATE;
2868  break;
2869 
2870  case DI_PRINT:
2871  if (DI_SUB_AUTHOR != (nSubType & DI_SUB_MASK) &&
2872  GetExport().GetNumberFormat(*pField, sStr))
2873  eField = ww::ePRINTDATE;
2874  break;
2875  case DI_EDIT:
2876  if( DI_SUB_AUTHOR != (nSubType & DI_SUB_MASK ) &&
2877  GetExport().GetNumberFormat( *pField, sStr ))
2878  eField = ww::eSAVEDATE;
2879  else
2880  eField = ww::eEDITTIME;
2881  break;
2882  case DI_CUSTOM:
2883  eField = ww::eDOCPROPERTY;
2884  {
2885  const SwDocInfoField * pDocInfoField =
2886  dynamic_cast<const SwDocInfoField *> (pField);
2887 
2888  if (pDocInfoField != nullptr)
2889  {
2890  OUString sFieldname = pDocInfoField->GetFieldName();
2891 
2892  const sal_Int32 nIndex = sFieldname.indexOf(':');
2893  if (nIndex >= 0)
2894  sFieldname = sFieldname.copy(nIndex + 1);
2895 
2896  sStr = "\"" + sFieldname + "\"";
2897  }
2898  }
2899  break;
2900  default:
2901  break;
2902  }
2903 
2904  if (eField != ww::eNONE)
2905  {
2906  GetExport().OutputField(pField, eField, FieldString(eField) + sStr);
2907  }
2908  else
2909  bWriteExpand = true;
2910  }
2911  break;
2912  case SwFieldIds::DateTime:
2913  {
2914  OUString sStr;
2915  if (!GetExport().GetNumberFormat(*pField, sStr))
2916  bWriteExpand = true;
2917  else
2918  {
2919  ww::eField eField = (DATEFLD & nSubType) ? ww::eDATE : ww::eTIME;
2920  GetExport().OutputField(pField, eField, FieldString(eField) + sStr);
2921  }
2922  }
2923  break;
2924  case SwFieldIds::DocStat:
2925  {
2927 
2928  switch (nSubType)
2929  {
2930  case DS_PAGE:
2931  eField = ww::eNUMPAGES;
2932  break;
2933  case DS_WORD:
2934  eField = ww::eNUMWORDS;
2935  break;
2936  case DS_CHAR:
2937  eField = ww::eNUMCHARS;
2938  break;
2939  }
2940 
2941  if (eField != ww::eNONE)
2942  {
2943  OUString sStr = FieldString(eField);
2944  GetNumberPara(sStr, *pField);
2945  GetExport().OutputField(pField, eField, sStr);
2946  }
2947  else
2948  bWriteExpand = true;
2949  }
2950  break;
2951  case SwFieldIds::ExtUser:
2952  {
2954  switch (0xFF & nSubType)
2955  {
2956  case EU_FIRSTNAME:
2957  case EU_NAME:
2958  eField = ww::eUSERNAME;
2959  break;
2960  case EU_SHORTCUT:
2961  eField = ww::eUSERINITIALS;
2962  break;
2963  case EU_STREET:
2964  case EU_COUNTRY:
2965  case EU_ZIP:
2966  case EU_CITY:
2967  eField = ww::eUSERADDRESS;
2968  break;
2969  }
2970 
2971  if (eField != ww::eNONE)
2972  {
2973  GetExport().OutputField(pField, eField, FieldString(eField));
2974  }
2975  else
2976  bWriteExpand = true;
2977  }
2978  break;
2980  {
2981  OUString sRet(static_cast<SwAuthorityField const*>(pField)
2982  ->ExpandCitation(AUTH_FIELD_IDENTIFIER, nullptr));
2983  // FIXME: DomainMapper_Impl::CloseFieldCommand() stuffs fully formed
2984  // field instructions in here, but if the field doesn't originate
2985  // from those filters it won't have that
2986  if (!sRet.trim().startsWith("CITATION"))
2987  {
2988  sRet = FieldString(ww::eCITATION) + " \"" + sRet + "\"";
2989  }
2990  GetExport().OutputField( pField, ww::eCITATION, sRet );
2991  }
2992  break;
2993  case SwFieldIds::Postit:
2994  //Sadly only possible for word in main document text
2995  if (GetExport().m_nTextTyp == TXT_MAINTEXT)
2996  {
2997  PostitField( pField );
2998  }
2999  break;
3000  case SwFieldIds::Input:
3001  {
3002  const SwInputField * pInputField = dynamic_cast<const SwInputField *>(pField);
3003 
3004  if (pInputField && pInputField->isFormField())
3005  GetExport().DoFormText(pInputField);
3006  else
3007  {
3008  const OUString sStr = FieldString(ww::eFILLIN) + "\""
3009  + pField->GetPar2() + "\"";
3010 
3011  GetExport().OutputField(pField, ww::eFILLIN, sStr);
3012  }
3013  }
3014  break;
3015  case SwFieldIds::GetRef:
3016  {
3018  OUString sStr;
3019  const SwGetRefField& rRField = *static_cast<const SwGetRefField*>(pField);
3020  switch (nSubType)
3021  {
3022  case REF_SETREFATTR:
3023  case REF_BOOKMARK:
3024  switch (pField->GetFormat())
3025  {
3026  case REF_PAGE_PGDESC:
3027  case REF_PAGE:
3028  eField = ww::ePAGEREF;
3029  break;
3030  default:
3031  eField = ww::eREF;
3032  break;
3033  }
3034  {
3035  const OUString& aRefName(rRField.GetSetRefName());
3036  sStr = FieldString(eField)
3037  + MSWordExportBase::GetBookmarkName(nSubType, &aRefName, 0);
3038  }
3039  switch (pField->GetFormat())
3040  {
3041  case REF_NUMBER:
3042  sStr += " \\r";
3043  break;
3044  case REF_NUMBER_NO_CONTEXT:
3045  sStr += " \\n";
3046  break;
3048  sStr += " \\w";
3049  break;
3050  }
3051  break;
3052  case REF_SEQUENCEFLD:
3053  {
3054  // Not implemented for RTF
3055  if(GetExport().GetExportFormat() == MSWordExportBase::ExportFormat::RTF)
3056  break;
3057 
3058  switch (pField->GetFormat())
3059  {
3060  case REF_PAGE:
3061  case REF_PAGE_PGDESC:
3062  eField = ww::ePAGEREF;
3063  break;
3064  default:
3065  eField = ww::eREF;
3066  break;
3067  }
3068  // Generate a unique bookmark name
3069  {
3070  OUString sName{rRField.GetSetRefName() + OUString::number(rRField.GetSeqNo())};
3071  switch (pField->GetFormat())
3072  {
3073  case REF_PAGE:
3074  case REF_PAGE_PGDESC:
3075  case REF_CONTENT:
3076  case REF_UPDOWN:
3077  sName += "_full";
3078  break;
3079  case REF_ONLYNUMBER:
3080  sName += "_label_and_number";
3081  break;
3082  case REF_ONLYCAPTION:
3083  sName += "_caption_only";
3084  break;
3085  case REF_ONLYSEQNO:
3086  sName += "_number_only";
3087  break;
3088  default: // Ignore other types of reference fields
3089  eField = ww::eNONE;
3090  break;
3091  }
3092  sStr = FieldString(eField) + MSWordExportBase::GetBookmarkName(nSubType, &sName, 0);
3093  }
3094  switch (pField->GetFormat())
3095  {
3096  case REF_NUMBER:
3097  sStr += " \\r";
3098  break;
3099  case REF_NUMBER_NO_CONTEXT:
3100  sStr += " \\n";
3101  break;
3103  sStr += " \\w";
3104  break;
3105  }
3106  break;
3107  }
3108  case REF_FOOTNOTE:
3109  case REF_ENDNOTE:
3110  switch (pField->GetFormat())
3111  {
3112  case REF_PAGE_PGDESC:
3113  case REF_PAGE:
3114  eField = ww::ePAGEREF;
3115  break;
3116  case REF_UPDOWN:
3117  eField = ww::eREF;
3118  break;
3119  default:
3120  eField =
3121  REF_ENDNOTE == nSubType ? ww::eNOTEREF : ww::eFOOTREF;
3122  break;
3123  }
3124  sStr = FieldString(eField)
3125  + MSWordExportBase::GetBookmarkName(nSubType, nullptr, rRField.GetSeqNo());
3126  break;
3127  }
3128 
3129  if (eField != ww::eNONE)
3130  {
3131  switch (pField->GetFormat())
3132  {
3133  case REF_UPDOWN:
3134  sStr += " \\p \\h "; // with hyperlink
3135  break;
3136  case REF_CHAPTER:
3137  sStr += " \\n \\h "; // with hyperlink
3138  break;
3139  default:
3140  sStr += " \\h "; // insert hyperlink
3141  break;
3142  }
3143  GetExport().OutputField(pField, eField, sStr);
3144  }
3145  else
3146  bWriteExpand = true;
3147  }
3148  break;
3150  {
3151  /*
3152  We need a font size to fill in the defaults, if these are overridden
3153  (as they generally are) by character properties then those properties
3154  win.
3155 
3156  The fontsize that is used in MS for determining the defaults is always
3157  the CJK fontsize even if the text is not in that language, in OOo the
3158  largest fontsize used in the field is the one we should take, but
3159  whatever we do, word will actually render using the fontsize set for
3160  CJK text. Nevertheless we attempt to guess whether the script is in
3161  asian or western text based up on the first character and use the
3162  font size of that script as our default.
3163  */
3165  sal_uInt16 nScript = g_pBreakIt->GetBreakIter()->getScriptType( pField->GetPar1(), 0);
3166 
3167  tools::Long nHeight = static_cast<const SvxFontHeightItem&>((GetExport().GetItem(
3169 
3170  nHeight = (nHeight + 10) / 20; //Font Size in points;
3171 
3172  /*
3173  Divide the combined char string into its up and down part. Get the
3174  font size and fill in the defaults as up == half the font size and
3175  down == a fifth the font size
3176  */
3177  const sal_Int32 nAbove = (pField->GetPar1().getLength()+1)/2;
3178  const OUString sStr = FieldString(ww::eEQ)
3179  + "\\o (\\s\\up "
3180  + OUString::number(nHeight/2)
3181  + "("
3182  + pField->GetPar1().subView(0, nAbove)
3183  + "), \\s\\do "
3184  + OUString::number(nHeight/5)
3185  + "("
3186  + pField->GetPar1().subView(nAbove)
3187  + "))";
3188  GetExport().OutputField(pField, ww::eEQ, sStr);
3189  }
3190  break;
3191  case SwFieldIds::Dropdown:
3192  bWriteExpand = DropdownField( pField );
3193  break;
3194  case SwFieldIds::Chapter:
3195  bWriteExpand = true;
3196  if (GetExport().m_bOutKF && rField.GetTextField())
3197  {
3198  const SwTextNode *pTextNd = GetExport().GetHdFtPageRoot();
3199  if (!pTextNd)
3200  {
3201  pTextNd = GetExport().m_pCurPam->GetNode().GetTextNode();
3202  }
3203 
3204  if (pTextNd)
3205  {
3206  SwChapterField aCopy(*static_cast<const SwChapterField*>(pField));
3207  aCopy.ChangeExpansion(*pTextNd, false);
3208  const OUString sStr = FieldString(ww::eSTYLEREF)
3209  + " "
3210  + OUString::number(aCopy.GetLevel() + 1)
3211  + " \\* MERGEFORMAT ";
3212  GetExport().OutputField(pField, ww::eSTYLEREF, sStr);
3213  bWriteExpand = false;
3214  }
3215  }
3216  break;
3218  {
3219  OUString sExpand(pField->GetPar2());
3220  if (!sExpand.isEmpty())
3221  {
3222  HiddenField( *pField );
3223  }
3224  }
3225  break;
3226  case SwFieldIds::JumpEdit:
3227  bWriteExpand = PlaceholderField( pField );
3228  break;
3229  case SwFieldIds::Macro:
3230  {
3231  const OUString sStr = " MACROBUTTON"
3232  + pField->GetPar1().replaceFirst("StarOffice.Standard.Modul1.", " ")
3233  + " "
3234  + lcl_GetExpandedField(*pField);
3235  GetExport().OutputField( pField, ww::eMACROBUTTON, sStr );
3236  }
3237  break;
3238  case SwFieldIds::Table:
3239  {
3240  ww::eField eField = ww::eEquals;
3241  OUString aExpand = " =" + pField->GetFieldName().trim();
3242  GetExport().OutputField(pField, eField, aExpand);
3243  }
3244  break;
3245  case SwFieldIds::User:
3246  {
3247  ww::eField eField = ww::eDOCVARIABLE;
3248  OUString aExpand = FieldString(eField) + pField->GetPar1() + " ";
3249  GetExport().OutputField(pField, eField, aExpand);
3250  }
3251  break;
3252  default:
3253  bWriteExpand = true;
3254  break;
3255  }
3256 
3257  if (bWriteExpand)
3258  WriteExpand( pField );
3259 }
3260 
3262 {
3263  if ( auto pTextNd = dynamic_cast< const SwContentNode *>( GetExport().m_pOutFormatNode ) )
3264  {
3265  Point const origin;
3266  Point aLayPos = pTextNd->FindLayoutRect( false, &origin ).Pos();
3267 
3268  SwPosition aPos( *pTextNd );
3269  ww8::Frame aFrame( *rFlyContent.GetFrameFormat(), aPos );
3270 
3271  OutputFlyFrame_Impl( aFrame, aLayPos );
3272  }
3273 }
3274 
3275 // TOXMarks are still missing
3276 
3277 // WW allows detailed settings for hyphenation only for the whole document.
3278 // One could implement following mimic: The values of the style "Standard" will
3279 // be set in the Document Properties ( DOP ) if they exist.
3280 
3281 // ACK. This suggestion fits exactly to our implementation of the import,
3282 // therefore I'll implement that right now. (KHZ, 07/15/2000)
3284 {
3285  // sprmPFNoAutoHyph
3286  m_rWW8Export.InsUInt16( NS_sprm::PFNoAutoHyph::val );
3287 
3288  m_rWW8Export.pO->push_back( rHyphenZone.IsHyphen() ? 0 : 1 );
3289 }
3290 
3292 {
3293  m_rWW8Export.InsUInt16( NS_sprm::PFAutoSpaceDE::val );
3294  m_rWW8Export.pO->push_back( rScriptSpace.GetValue() ? 1 : 0 );
3295 }
3296 
3298 {
3299  m_rWW8Export.InsUInt16( NS_sprm::PFOverflowPunct::val );
3300  m_rWW8Export.pO->push_back( rItem.GetValue() ? 1 : 0 );
3301 }
3302 
3304 {
3305  m_rWW8Export.InsUInt16( NS_sprm::PFKinsoku::val );
3306  m_rWW8Export.pO->push_back( rItem.GetValue() ? 1 : 0 );
3307 }
3308 
3310 {
3311  // sprmPFUsePgsuSettings
3312 
3313  m_rWW8Export.InsUInt16( NS_sprm::PFUsePgsuSettings::val );
3314  m_rWW8Export.pO->push_back( rGrid.GetValue() ? 1 : 0 );
3315 }
3316 
3318 {
3319  // sprmPWAlignFont
3320 
3321  m_rWW8Export.InsUInt16( NS_sprm::PWAlignFont::val );
3322 
3323  SvxParaVertAlignItem::Align nAlign = rAlign.GetValue();
3324  sal_uInt16 nVal;
3325  switch ( nAlign )
3326  {
3328  nVal = 2;
3329  break;
3331  nVal = 0;
3332  break;
3334  nVal = 1;
3335  break;
3337  nVal = 3;
3338  break;
3340  nVal = 4;
3341  break;
3342  default:
3343  nVal = 4;
3344  OSL_FAIL( "Unknown vert alignment" );
3345  break;
3346  }
3347  m_rWW8Export.InsUInt16( nVal );
3348 }
3349 
3350 // NoHyphen: I didn't find an equal in the SW UI and WW UI
3351 
3352 // RefMark, NoLineBreakHere are still missing
3353 
3355 {
3356  ww::bytes aAttrArr;
3357  const bool bAutoNum = rFootnote.GetNumStr().isEmpty();
3358  if( bAutoNum )
3359  {
3360  static const sal_uInt8 aSpec[] =
3361  {
3362  0x03, 0x6a, 0, 0, 0, 0, // sprmCObjLocation
3363  0x55, 0x08, 1 // sprmCFSpec
3364  };
3365 
3366  aAttrArr.insert(aAttrArr.end(), aSpec, aSpec+sizeof(aSpec));
3367  }
3368 
3369  // sprmCIstd
3370  const SwEndNoteInfo* pInfo;
3371  if( rFootnote.IsEndNote() )
3372  pInfo = &m_rDoc.GetEndNoteInfo();
3373  else
3374  pInfo = &m_rDoc.GetFootnoteInfo();
3375  const SwCharFormat* pCFormat = pOutArr
3376  ? pInfo->GetAnchorCharFormat( m_rDoc )
3377  : pInfo->GetCharFormat( m_rDoc );
3379  SwWW8Writer::InsUInt16( aAttrArr, GetId( pCFormat ) );
3380 
3381  // fSpec-Attribut true
3382  // For Auto-Number a special character must go
3383  // into the text and therefore a fSpec attribute
3384  m_pChpPlc->AppendFkpEntry( Strm().Tell() );
3385  if( bAutoNum )
3386  WriteChar( 0x02 ); // auto number character
3387  else
3388  // user numbering
3389  OutSwString(rFootnote.GetNumStr(), 0, rFootnote.GetNumStr().getLength());
3390 
3391  if( pOutArr )
3392  {
3393  // insert at start of array, so the "hard" attribute overrule the
3394  // attributes of the character template
3395  pOutArr->insert( pOutArr->begin(), aAttrArr.begin(), aAttrArr.end() );
3396  }
3397  else
3398  {
3399  std::unique_ptr<ww::bytes> pOwnOutArr(new ww::bytes);
3400 
3401  // insert at start of array, so the "hard" attribute overrule the
3402  // attributes of the character template
3403  pOwnOutArr->insert(pOwnOutArr->begin(), aAttrArr.begin(), aAttrArr.end());
3404 
3405  // write for the ftn number in the content, the font of the anchor
3406  const SwTextFootnote* pTextFootnote = rFootnote.GetTextFootnote();
3407  if( pTextFootnote )
3408  {
3409  std::unique_ptr<ww::bytes> pOld = std::move(pO);
3410  pO = std::move(pOwnOutArr);
3412  RES_CHRATR_FONT>{} );
3413 
3414  pCFormat = pInfo->GetCharFormat( m_rDoc );
3415 
3416  pTextFootnote->GetTextNode().GetParaAttr(aSet,
3417  pTextFootnote->GetStart(), pTextFootnote->GetStart() + 1, true);
3418  if (aSet.Count())
3419  {
3420  m_pAttrOutput->OutputItem( aSet.Get( RES_CHRATR_FONT ) );
3421  }
3422  else
3423  {
3424  m_pAttrOutput->OutputItem( pCFormat->GetAttrSet().Get(RES_CHRATR_FONT) );
3425  }
3426  pOwnOutArr = std::move(pO);
3427  pO = std::move(pOld);
3428  }
3429  m_pChpPlc->AppendFkpEntry( Strm().Tell(), pOwnOutArr->size(),
3430  pOwnOutArr->data() );
3431  }
3432 }
3433 
3434 static bool lcl_IsAtTextEnd(const SwFormatFootnote& rFootnote)
3435 {
3436  bool bRet = true;
3437  if( rFootnote.GetTextFootnote() )
3438  {
3439  sal_uInt16 nWh = rFootnote.IsEndNote() ? sal_uInt16(RES_END_AT_TXTEND)
3440  : sal_uInt16(RES_FTN_AT_TXTEND);
3441  const SwSectionNode* pSectNd = rFootnote.GetTextFootnote()->GetTextNode().
3442  FindSectionNode();
3443  while( pSectNd && FTNEND_ATPGORDOCEND ==
3444  static_cast<const SwFormatFootnoteEndAtTextEnd&>(pSectNd->GetSection().GetFormat()->
3445  GetFormatAttr( nWh)).GetValue() )
3446  pSectNd = pSectNd->StartOfSectionNode()->FindSectionNode();
3447 
3448  if (!pSectNd)
3449  bRet = false; // the is ftn/end collected at Page- or Doc-End
3450  }
3451  return bRet;
3452 }
3453 
3455 {
3456  sal_uInt16 nTyp;
3457  if ( rFootnote.IsEndNote() )
3458  {
3459  nTyp = REF_ENDNOTE;
3460  if ( GetExport().m_bEndAtTextEnd )
3461  GetExport().m_bEndAtTextEnd = lcl_IsAtTextEnd( rFootnote );
3462  }
3463  else
3464  {
3465  nTyp = REF_FOOTNOTE;
3466  if ( GetExport().m_bFootnoteAtTextEnd )
3467  GetExport().m_bFootnoteAtTextEnd = lcl_IsAtTextEnd( rFootnote );
3468  }
3469 
3470  // if any reference to this footnote/endnote then insert an internal
3471  // Bookmark.
3472  OUString sBkmkNm;
3473  if ( GetExport().HasRefToFootOrEndnote( rFootnote.IsEndNote(), rFootnote.GetTextFootnote()->GetSeqRefNo()))
3474  {
3475  sBkmkNm = MSWordExportBase::GetBookmarkName( nTyp, nullptr,
3476  rFootnote.GetTextFootnote()->GetSeqRefNo() );
3477  GetExport().AppendBookmark( sBkmkNm );
3478  }
3479 
3480  TextFootnote_Impl( rFootnote );
3481 
3482  if ( !sBkmkNm.isEmpty() )
3483  GetExport().AppendBookmark( sBkmkNm ); // FIXME: Why is it added twice? Shouldn't this one go to WW8AttributeOutput::TextFootnote_Impl()?
3484 }
3485 
3487 {
3488  WW8_WrPlcFootnoteEdn* pFootnoteEnd;
3489  if ( rFootnote.IsEndNote() || GetExport().m_rDoc.GetFootnoteInfo().m_ePos == FTNPOS_CHAPTER )
3490  pFootnoteEnd = m_rWW8Export.pEdn.get();
3491  else
3492  pFootnoteEnd = m_rWW8Export.pFootnote.get();
3493 
3494  pFootnoteEnd->Append( m_rWW8Export.Fc2Cp( m_rWW8Export.Strm().Tell() ), rFootnote );
3495  m_rWW8Export.WriteFootnoteBegin( rFootnote, m_rWW8Export.pO.get() );
3496 }
3497 
3499 {
3500  if( rCharFormat.GetCharFormat() )
3501  {
3502  m_rWW8Export.InsUInt16( NS_sprm::CIstd::val );
3503 
3504  m_rWW8Export.InsUInt16( m_rWW8Export.GetId( rCharFormat.GetCharFormat() ) );
3505  }
3506 }
3507 
3508 /*
3509  See ww8par6.cxx Read_DoubleLine for some more info
3510  */
3512 {
3513  // #i28331# - check that bOn is set
3514  if ( !rTwoLines.GetValue() )
3515  return;
3516 
3517  m_rWW8Export.InsUInt16( NS_sprm::CFELayout::val );
3518  m_rWW8Export.pO->push_back( sal_uInt8(0x06) ); //len 6
3519  m_rWW8Export.pO->push_back( sal_uInt8(0x02) );
3520 
3521  sal_Unicode cStart = rTwoLines.GetStartBracket();
3522  sal_Unicode cEnd = rTwoLines.GetEndBracket();
3523 
3524  /*
3525  As per usual we have problems. We can have separate left and right brackets
3526  in OOo, it doesn't appear that you can in word. Also in word there appear
3527  to only be a limited number of possibilities, we can use pretty much
3528  anything.
3529 
3530  So if we have none, we export none, if either bracket is set to a known
3531  word type we export both as that type (with the bracket winning out in
3532  the case of a conflict simply being the order of test here.
3533 
3534  Upshot being a documented created in word will be reexported with no
3535  ill effects.
3536  */
3537 
3538  sal_uInt16 nType;
3539  if (!cStart && !cEnd)
3540  nType = 0;
3541  else if ((cStart == '{') || (cEnd == '}'))
3542  nType = 4;
3543  else if ((cStart == '<') || (cEnd == '>'))
3544  nType = 3;
3545  else if ((cStart == '[') || (cEnd == ']'))
3546  nType = 2;
3547  else
3548  nType = 1;
3549  m_rWW8Export.InsUInt16( nType );
3550  static const sal_uInt8 aZeroArr[ 3 ] = { 0, 0, 0 };
3551  m_rWW8Export.pO->insert( m_rWW8Export.pO->end(), aZeroArr, aZeroArr+3);
3552 }
3553 
3555 {
3556  const SwTextNode* pTextNd = nullptr;
3557  if (rNumRule.GetValue().isEmpty())
3558  {
3559  ParaNumRule_Impl(pTextNd, 0, 0);
3560  return;
3561  }
3562  const SwNumRule* pRule = GetExport().m_rDoc.FindNumRulePtr(
3563  rNumRule.GetValue() );
3564  if (!pRule)
3565  return;
3566 
3567  sal_uInt16 nNumId = GetExport().GetNumberingId(*pRule) + 1;
3568  sal_uInt8 nLvl = 0;
3569 
3570  if (!GetExport().m_pOutFormatNode)
3571  {
3572  ParaNumRule_Impl(pTextNd, nLvl, nNumId);
3573  return;
3574  }
3575 
3576  if ( dynamic_cast< const SwContentNode *>( GetExport().m_pOutFormatNode ) != nullptr )
3577  {
3578  pTextNd = static_cast<const SwTextNode*>(GetExport().m_pOutFormatNode);
3579 
3580  if( pTextNd->IsCountedInList())
3581  {
3582  int nLevel = pTextNd->GetActualListLevel();
3583 
3584  if (nLevel < 0)
3585  nLevel = 0;
3586 
3587  if (nLevel >= MAXLEVEL)
3588  nLevel = MAXLEVEL - 1;
3589 
3590  nLvl = static_cast< sal_uInt8 >(nLevel);
3591 
3592  if (GetExport().GetExportFormat() == MSWordExportBase::DOCX) // FIXME
3593  {
3594  // tdf#95848 find the abstract list definition
3595  OUString const listId(pTextNd->GetListId());
3596  if (!listId.isEmpty()
3597  && (listId != pRule->GetDefaultListId() // default list id uses the 1:1 mapping
3598  || pTextNd->IsListRestart()) // or restarting previous list
3599  )
3600  {
3601  SwList const*const pList(
3602  GetExport().m_rDoc.getIDocumentListsAccess().getListByName(listId));
3603  if (pList)
3604  {
3605  SwNumRule const*const pAbstractRule(
3606  GetExport().m_rDoc.FindNumRulePtr(
3607  pList->GetDefaultListStyleName()));
3608  assert(pAbstractRule);
3609  if (pAbstractRule == pRule && !pTextNd->IsListRestart())
3610  {
3611  // different list, but no override
3612  nNumId = GetExport().DuplicateAbsNum(listId, *pAbstractRule) + 1;
3613  }
3614  else
3615  {
3616  nNumId = GetExport().OverrideNumRule(
3617  *pRule, listId, *pAbstractRule) + 1;
3618 
3619  if (pTextNd->IsListRestart())
3620  {
3621  // For restarted lists we should also keep value for
3622  // future w:lvlOverride / w:startOverride
3623  GetExport().AddListLevelOverride(nNumId-1, pTextNd->GetActualListLevel(),
3624  pTextNd->GetActualListStartValue());
3625  }
3626  }
3627  }
3628  }
3629  }
3630  }
3631  else
3632  {
3633  // #i44815# adjust numbering for numbered paragraphs
3634  // without number (NO_NUMLEVEL). These paragraphs
3635  // will receive a list id 0, which WW interprets as
3636  // 'no number'.
3637  nNumId = 0;
3638  }
3639  }
3640  else if ( auto pC = dynamic_cast< const SwTextFormatColl *>( GetExport().m_pOutFormatNode ) )
3641  {
3642  if ( pC && pC->IsAssignedToListLevelOfOutlineStyle() )
3643  nLvl = static_cast< sal_uInt8 >( pC->GetAssignedOutlineStyleLevel() );
3644  }
3645 
3646  if ( nLvl >= WW8ListManager::nMaxLevel )
3647  nLvl = WW8ListManager::nMaxLevel - 1;
3648 
3649  ParaNumRule_Impl( pTextNd, nLvl, nNumId);
3650 }
3651 
3653  sal_Int32 const nLvl, sal_Int32 const nNumId)
3654 {
3655  if (USHRT_MAX == nNumId)
3656  return;
3657 
3658  // write sprmPIlvl and sprmPIlfo
3659  SwWW8Writer::InsUInt16( *m_rWW8Export.pO, NS_sprm::PIlvl::val );
3660  m_rWW8Export.pO->push_back( ::sal::static_int_cast<sal_uInt8>(nLvl) );
3661  SwWW8Writer::InsUInt16( *m_rWW8Export.pO, NS_sprm::PIlfo::val );
3662  SwWW8Writer::InsUInt16( *m_rWW8Export.pO, ::sal::static_int_cast<sal_uInt16>(nNumId) );
3663 }
3664 
3665 /* File FRMATR.HXX */
3666 
3668 {
3669  if( m_rWW8Export.m_bOutFlyFrameAttrs ) // Flys
3670  {
3671  if( m_rWW8Export.m_bOutGrf )
3672  return; // Fly around graphic -> Auto-size
3673 
3674  //???? What about percentages ???
3675  if ( rSize.GetWidth() && rSize.GetWidthSizeType() == SwFrameSize::Fixed)
3676  {
3677  //"sprmPDxaWidth"
3678  m_rWW8Export.InsUInt16( NS_sprm::PDxaWidth::val );
3679  m_rWW8Export.InsUInt16( static_cast<sal_uInt16>(rSize.GetWidth()) );
3680  }
3681 
3682  if ( rSize.GetHeight() )
3683  {
3684  // sprmPWHeightAbs
3685  m_rWW8Export.InsUInt16( NS_sprm::PWHeightAbs::val );
3686 
3687  sal_uInt16 nH = 0;
3688  switch ( rSize.GetHeightSizeType() )
3689  {
3690  case SwFrameSize::Variable: break;
3691  case SwFrameSize::Fixed: nH = static_cast<sal_uInt16>(rSize.GetHeight()) & 0x7fff; break;
3692  default: nH = static_cast<sal_uInt16>(rSize.GetHeight()) | 0x8000; break;
3693  }
3694  m_rWW8Export.InsUInt16( nH );
3695  }
3696  }
3697  else if( m_rWW8Export.m_bOutPageDescs ) // PageDesc : width + height
3698  {
3699  if( m_rWW8Export.m_pCurrentPageDesc->GetLandscape() )
3700  {
3701  /*sprmSBOrientation*/
3702  m_rWW8Export.InsUInt16( NS_sprm::SBOrientation::val );
3703  m_rWW8Export.pO->push_back( 2 );
3704  }
3705 
3706  /*sprmSXaPage*/
3707  m_rWW8Export.InsUInt16( NS_sprm::SXaPage::val );
3708  m_rWW8Export.InsUInt16(
3709  msword_cast<sal_uInt16>(SvxPaperInfo::GetSloppyPaperDimension(rSize.GetWidth())));
3710 
3711  /*sprmSYaPage*/
3712  m_rWW8Export.InsUInt16( NS_sprm::SYaPage::val );
3713  m_rWW8Export.InsUInt16(
3714  msword_cast<sal_uInt16>(SvxPaperInfo::GetSloppyPaperDimension(rSize.GetHeight())));
3715  }
3716 }
3717 
3718 // FillOrder is still missing
3719 
3728 {
3729  OSL_ENSURE( nChar, "replaced with 0 crashes WW97/95" );
3730 
3731  bool bReplaced = false;
3732  SvStream& rStrm = Strm();
3733  sal_uLong nRetPos = 0, nPos = rStrm.Tell();
3734  //If there is at least two characters already output
3735  if (nPos - 2 >= o3tl::make_unsigned(pFib->m_fcMin))
3736  {
3737  sal_uInt16 nUCode=0;
3738 
3739  rStrm.SeekRel(-2);
3740  rStrm.ReadUInt16( nUCode );
3741  //If the last char was a cr
3742  if (nUCode == 0x0d) // CR ?
3743  {
3744  if ((nChar == 0x0c) &&
3745  (nPos - 4 >= o3tl::make_unsigned(pFib->m_fcMin)))
3746  {
3747  rStrm.SeekRel(-4);
3748  rStrm.ReadUInt16( nUCode );
3749  }
3750  else
3751  {
3752  rStrm.SeekRel(-2);
3753  nUCode = 0x0;
3754  }
3755  //And the para is not of len 0, then replace this cr with the mark
3756  //#120140# If there is a cr before a column break, need replace the cr. So remove the "nChar==0x0e" check.
3757  if( nUCode == 0x0d )
3758  bReplaced = false;
3759  else
3760  {
3761  bReplaced = true;
3762  WriteChar(nChar);
3763  nRetPos = nPos;
3764  }
3765  }
3766  else if ((nUCode == 0x0c) && (nChar == 0x0e))
3767  {
3768  // a column break after a section has no effect in writer
3769  bReplaced = true;
3770  }
3771  rStrm.Seek( nPos );
3772  }
3773  else
3774  bReplaced = true;
3775 
3776  if (!bReplaced)
3777  {
3778  // then write as normal char
3779  WriteChar(nChar);
3780  m_pPiece->SetParaBreak();
3781  m_pPapPlc->AppendFkpEntry(rStrm.Tell());
3782  m_pChpPlc->AppendFkpEntry(rStrm.Tell());
3783  nRetPos = rStrm.Tell();
3784  }
3785  return nRetPos;
3786 }
3787 
3788 void WW8AttributeOutput::TableRowEnd(sal_uInt32 nDepth)
3789 {
3790  if ( nDepth == 1 )
3791  m_rWW8Export.WriteChar( 0x07 );
3792  else if ( nDepth > 1 )
3793  m_rWW8Export.WriteChar( 0x0d );
3794 
3795  //Technically in a word document this is a different value for a row ends
3796  //that are not row ends directly after a cell with a graphic. But it
3797  //doesn't seem to make a difference
3798  //pMagicTable->Append(Fc2Cp(Strm().Tell()),0x1B6);
3799 }
3800 
3802 {
3803  if ( GetExport().m_bStyDef )
3804  if (auto pC = dynamic_cast< const SwTextFormatColl *>( GetExport().m_pOutFormatNode ) )
3805  {
3806  if ( (SfxItemState::SET != pC->GetItemState( RES_BREAK, false ) ) && rPageDesc.KnowsPageDesc() )
3807  FormatBreak( SvxFormatBreakItem( SvxBreak::PageBefore, RES_BREAK ) );
3808  }
3809 }
3810 
3812 {
3813  // sprmPPageBreakBefore/sprmPFPageBreakBefore
3814  m_rWW8Export.InsUInt16( NS_sprm::PFPageBreakBefore::val );
3815 
3816  m_rWW8Export.pO->push_back( bBreak ? 1 : 0 );
3817 }
3818 
3825 {
3826  if ( GetExport().m_bStyDef )
3827  {
3828  switch ( rBreak.GetBreak() )
3829  {
3830  case SvxBreak::NONE:
3831  case SvxBreak::PageBefore:
3832  case SvxBreak::PageBoth:
3833  PageBreakBefore( rBreak.GetValue() != SvxBreak::NONE );
3834  break;
3835  default:
3836  break;
3837  }
3838  }
3839  else if ( !GetExport().m_pParentFrame )
3840  {
3841  sal_uInt8 nC = 0;
3842  bool bBefore = false;
3843  // #i76300# - Note: Can only be <true>, if <bBefore> equals <false>.
3844  bool bCheckForFollowPageDesc = false;
3845 
3846  switch ( rBreak.GetBreak() )
3847  {
3848  case SvxBreak::NONE: // disabled
3849  if ( !GetExport().m_bBreakBefore )
3850  PageBreakBefore( false );
3851  return;
3852 
3853  case SvxBreak::ColumnBefore: // ColumnBreak
3854  bBefore = true;
3855  [[fallthrough]];
3856  case SvxBreak::ColumnAfter:
3857  case SvxBreak::ColumnBoth:
3858  if ( GetExport().m_rDoc.getIDocumentSettingAccess().get( DocumentSettingId::TREAT_SINGLE_COLUMN_BREAK_AS_PAGE_BREAK )
3859  || GetExport().Sections().CurrentNumberOfColumns( GetExport().m_rDoc ) > 1 )
3860  {
3861  nC = msword::ColumnBreak;
3862  }
3863  break;
3864 
3865  case SvxBreak::PageBefore: // PageBreak
3866  // From now on(fix for #i77900#) we prefer to save a page break
3867  // as paragraph attribute (if the exporter is OK with that),
3868  // this has to be done after the export of the paragraph ( =>
3869  // !GetExport().bBreakBefore )
3870  if (GetExport().PreferPageBreakBefore())
3871  {
3872  if (!GetExport().m_bBreakBefore)
3873  PageBreakBefore(true);
3874  }
3875  else
3876  {
3877  bBefore = true;
3878  nC = msword::PageBreak;
3879  }
3880  break;
3881  case SvxBreak::PageAfter:
3882  case SvxBreak::PageBoth:
3883  nC = msword::PageBreak;
3884  // #i76300# - check for follow page description,
3885  // if current writing attributes of a paragraph.
3886  if ( dynamic_cast< const SwTextNode* >( GetExport().m_pOutFormatNode ) &&
3887  GetExport().GetCurItemSet() )
3888  {
3889  bCheckForFollowPageDesc = true;
3890  }
3891  break;
3892 
3893  default:
3894  break;
3895  }
3896 
3897  if ( ( bBefore == GetExport().m_bBreakBefore ) && nC )
3898  {
3899  // #i76300#
3900  bool bFollowPageDescWritten = false;
3901  if ( bCheckForFollowPageDesc )
3902  {
3903  bFollowPageDescWritten =
3904  GetExport().OutputFollowPageDesc( GetExport().GetCurItemSet(),
3905  dynamic_cast<const SwTextNode*>( GetExport().m_pOutFormatNode ) );
3906  }
3907  if ( !bFollowPageDescWritten )
3908  {
3909  SectionBreak(nC, !bBefore);
3910  }
3911  }
3912  }
3913 }
3914 
3915 void WW8AttributeOutput::SectionBreak( sal_uInt8 nC, bool /*bBreakAfter*/, const WW8_SepInfo* /*pSectionInfo*/ )
3916 {
3917  m_rWW8Export.ReplaceCr( nC );
3918 }
3919 
3921 {
3922  MSWordStyles * pStyles = GetExport().m_pStyles.get();
3923  const SwFormat * pSwFormat = pStyles->GetSwFormat(0);
3924 
3925  sal_uInt32 nPageCharSize = 0;
3926 
3927  if (pSwFormat != nullptr)
3928  {
3929  nPageCharSize = ItemGet<SvxFontHeightItem>
3930  (*pSwFormat, RES_CHRATR_FONTSIZE).GetHeight();
3931  }
3932  sal_uInt16 nPitch = rGrid.IsSquaredMode() ? rGrid.GetBaseHeight() :
3933  rGrid.GetBaseWidth( );
3934 
3935  sal_Int32 nCharWidth = nPitch - nPageCharSize;
3936  sal_Int32 nFraction = nCharWidth % 20;
3937  if ( nCharWidth < 0 )
3938  nFraction = 20 + nFraction;
3939  nFraction = ( nFraction * 0xFFF ) / 20;
3940  nFraction = ( nFraction & 0x00000FFF );
3941 
3942  sal_Int32 nMain = nCharWidth / 20;
3943  if ( nCharWidth < 0 )
3944  nMain -= 1;
3945  nMain = nMain * 0x1000;
3946  nMain = ( nMain & 0xFFFFF000 );
3947 
3948  return sal_uInt32( nFraction + nMain );
3949 }
3950 
3952 {
3953  if (!m_rWW8Export.m_bOutPageDescs)
3954  return;
3955 
3956  sal_uInt16 nGridType = 0;
3957  switch ( rGrid.GetGridType() )
3958  {
3959  default:
3960  OSL_FAIL("Unknown grid type");
3961  [[fallthrough]];
3962  case GRID_NONE:
3963  nGridType = 0;
3964  break;
3965  case GRID_LINES_ONLY:
3966  nGridType = 2;
3967  break;
3968  case GRID_LINES_CHARS:
3969  if ( rGrid.IsSnapToChars() )
3970  nGridType = 3;
3971  else
3972  nGridType = 1;
3973  break;
3974  }
3975  m_rWW8Export.InsUInt16( NS_sprm::SClm::val );
3976  m_rWW8Export.InsUInt16( nGridType );
3977 
3978  sal_uInt16 nHeight = rGrid.GetBaseHeight() + rGrid.GetRubyHeight();
3979  m_rWW8Export.InsUInt16( NS_sprm::SDyaLinePitch::val );
3980  m_rWW8Export.InsUInt16( nHeight );
3981 
3982  m_rWW8Export.InsUInt16( NS_sprm::SDxtCharSpace::val );
3983  m_rWW8Export.InsUInt32( GridCharacterPitch( rGrid ) );
3984 }
3985 
3987 {
3988  if ( !m_rWW8Export.m_bOutPageDescs )
3989  return;
3990 
3991  sal_uInt16 nVal;
3992  switch ( rPaperBin.GetValue() )
3993  {
3994  case 0: nVal = 15; break; // Automatically select
3995  case 1: nVal = 1; break; // Upper paper tray
3996  case 2: nVal = 4; break; // Manual paper feed
3997  default: nVal = 0; break;
3998  }
3999 
4000  if ( nVal )
4001  {
4002  m_rWW8Export.InsUInt16( m_rWW8Export.m_bOutFirstPage
4004 
4005  m_rWW8Export.InsUInt16( nVal );
4006  }
4007 }
4008 
4010 {
4011  // Flys are still missing ( see RTF )
4012 
4013  if ( m_rWW8Export.m_bOutFlyFrameAttrs ) // Flys
4014  {
4015  // sprmPDxaFromText10
4016  m_rWW8Export.InsUInt16( NS_sprm::LN_PDxaFromText10 );
4017  // use average, since WW only knows one value
4018  m_rWW8Export.InsUInt16( static_cast<sal_uInt16>( ( rLR.GetLeft() + rLR.GetRight() ) / 2 ) );
4019  }
4020  else if ( m_rWW8Export.m_bOutPageDescs ) // PageDescs
4021  {
4022  m_pageMargins.nLeft = 0;
4023  m_pageMargins.nRight = 0;
4024 
4025  if ( auto pBoxItem = static_cast<const SvxBoxItem*>(m_rWW8Export.HasItem( RES_BOX )) )
4026  {
4027  m_pageMargins.nLeft = pBoxItem->CalcLineSpace( SvxBoxItemLine::LEFT, /*bEvenIfNoLine*/true );
4028  m_pageMargins.nRight = pBoxItem->CalcLineSpace( SvxBoxItemLine::RIGHT, /*bEvenIfNoLine*/true );
4029  }
4030 
4031  m_pageMargins.nLeft += sal::static_int_cast<sal_uInt16>(rLR.GetLeft());
4032  m_pageMargins.nRight += sal::static_int_cast<sal_uInt16>(rLR.GetRight());
4033 
4034  // sprmSDxaLeft
4035  m_rWW8Export.InsUInt16( NS_sprm::SDxaLeft::val );
4036  m_rWW8Export.InsUInt16( m_pageMargins.nLeft );
4037 
4038  // sprmSDxaRight
4039  m_rWW8Export.InsUInt16( NS_sprm::SDxaRight::val );
4040  m_rWW8Export.InsUInt16( m_pageMargins.nRight );
4041  }
4042  else
4043  { // normal paragraphs
4044  // sprmPDxaLeft
4045  m_rWW8Export.InsUInt16( 0x845E ); //asian version ?
4046  m_rWW8Export.InsUInt16( static_cast<sal_uInt16>(rLR.GetTextLeft()) );
4047 
4048  // sprmPDxaRight
4049  m_rWW8Export.InsUInt16( 0x845D ); //asian version ?
4050  m_rWW8Export.InsUInt16( static_cast<sal_uInt16>(rLR.GetRight()) );
4051 
4052  // sprmPDxaLeft1
4053  m_rWW8Export.InsUInt16( 0x8460 ); //asian version ?
4054  m_rWW8Export.InsUInt16( rLR.GetTextFirstLineOffset() );
4055  }
4056 }
4057 
4059 {
4060  // Flys are still missing ( see RTF )
4061 
4062  if ( m_rWW8Export.m_bOutFlyFrameAttrs ) // Flys
4063  {
4064  // sprmPDyaFromText
4065  m_rWW8Export.InsUInt16( NS_sprm::PDyaFromText::val );
4066  // use average, since WW only knows one value
4067  m_rWW8Export.InsUInt16( static_cast<sal_uInt16>( ( rUL.GetUpper() + rUL.GetLower() ) / 2 ) );
4068  }
4069  else if ( m_rWW8Export.m_bOutPageDescs ) // Page-UL
4070  {
4071  OSL_ENSURE( m_rWW8Export.GetCurItemSet(), "Impossible" );
4072  if ( !m_rWW8Export.GetCurItemSet() )
4073  return;
4074 
4075  HdFtDistanceGlue aDistances( *m_rWW8Export.GetCurItemSet() );
4076 
4077  if ( aDistances.HasHeader() )
4078  {
4079  //sprmSDyaHdrTop
4080  m_rWW8Export.InsUInt16( NS_sprm::SDyaHdrTop::val );
4081  m_rWW8Export.InsUInt16( aDistances.dyaHdrTop );
4082  }
4083 
4084  // sprmSDyaTop
4085  m_rWW8Export.InsUInt16( NS_sprm::SDyaTop::val );
4086  m_rWW8Export.InsUInt16( aDistances.dyaTop );
4087  m_pageMargins.nTop = aDistances.dyaTop;
4088 
4089  if ( aDistances.HasFooter() )
4090  {
4091  //sprmSDyaHdrBottom
4092  m_rWW8Export.InsUInt16( NS_sprm::SDyaHdrBottom::val );
4093  m_rWW8Export.InsUInt16( aDistances.dyaHdrBottom );
4094  }
4095 
4096  //sprmSDyaBottom
4097  m_rWW8Export.InsUInt16( NS_sprm::SDyaBottom::val );
4098  m_rWW8Export.InsUInt16( aDistances.dyaBottom );
4099  m_pageMargins.nBottom = aDistances.dyaBottom;
4100  }
4101  else
4102  {
4103  // sprmPDyaBefore
4104  m_rWW8Export.InsUInt16( NS_sprm::PDyaBefore::val );
4105  m_rWW8Export.InsUInt16( rUL.GetUpper() );
4106  // sprmPDyaAfter
4107  m_rWW8Export.InsUInt16( NS_sprm::PDyaAfter::val );
4108  m_rWW8Export.InsUInt16( rUL.GetLower() );
4109  // sprmPFContextualSpacing
4110  if (rUL.GetContext())
4111  {
4112  m_rWW8Export.InsUInt16(NS_sprm::PFContextualSpacing::val);
4113  m_rWW8Export.pO->push_back( static_cast<sal_uInt8>(rUL.GetContext()) );
4114  }
4115  }
4116 }
4117 
4118 // print, opaque, protect are still missing
4119 
4121 {
4122  if ( m_rWW8Export.m_bOutFlyFrameAttrs )
4123  {
4124  m_rWW8Export.InsUInt16( NS_sprm::PWr::val );
4125 
4126  m_rWW8Export.pO->push_back(
4127  ( css::text::WrapTextMode_NONE != rSurround.GetSurround() ) ? 2 : 1 );
4128  }
4129 }
4130 
4132 {
4133 
4135  if ( !m_rWW8Export.m_bOutFlyFrameAttrs )
4136  return;
4137 
4138  short nPos;
4139  switch( rFlyVert.GetVertOrient() )
4140  {
4142  nPos = static_cast<short>(rFlyVert.GetPos());
4143  break;
4144  case text::VertOrientation::CENTER:
4145  case text::VertOrientation::LINE_CENTER:
4146  nPos = -8;
4147  break;
4148  case text::VertOrientation::BOTTOM:
4149  case text::VertOrientation::LINE_BOTTOM:
4150  nPos = -12;
4151  break;
4152  case text::VertOrientation::TOP:
4153  case text::VertOrientation::LINE_TOP:
4154  default:
4155  nPos = -4;
4156  break;
4157  }
4158 
4159  // sprmPDyaAbs
4160  m_rWW8Export.InsUInt16( NS_sprm::PDyaAbs::val );
4161  m_rWW8Export.InsUInt16( nPos );
4162 }
4163 
4165 {
4166  if ( !m_rWW8Export.m_pParentFrame )
4167  {
4168  OSL_ENSURE( m_rWW8Export.m_pParentFrame, "HoriOrient without mpParentFrame !!" );
4169  return;
4170  }
4171 
4173  if ( !m_rWW8Export.m_bOutFlyFrameAttrs )
4174  return;
4175 
4176  short nPos;
4177  switch( rFlyHori.GetHoriOrient() )
4178  {
4180  nPos = static_cast<short>(rFlyHori.GetPos());
4181  if( !nPos )
4182  nPos = 1; // WW: 0 is reserved
4183  break;
4184  case text::HoriOrientation::LEFT:
4185  nPos = rFlyHori.IsPosToggle() ? -12 : 0;
4186  break;
4187  case text::HoriOrientation::RIGHT:
4188  nPos = rFlyHori.IsPosToggle() ? -16 : -8;
4189  break;
4190  case text::HoriOrientation::CENTER:
4191  case text::HoriOrientation::FULL: // FULL only for tables
4192  default:
4193  nPos = -4;
4194  break;
4195  }
4196 
4197  // sprmPDxaAbs
4198  m_rWW8Export.InsUInt16( NS_sprm::PDxaAbs::val );
4199  m_rWW8Export.InsUInt16( nPos );
4200 }
4201 
4203 {
4204  OSL_ENSURE( m_rWW8Export.m_pParentFrame, "Anchor without mpParentFrame !!" );
4205 
4206  if ( !m_rWW8Export.m_bOutFlyFrameAttrs )
4207  return;
4208 
4209  sal_uInt8 nP = 0;
4210  switch ( rAnchor.GetAnchorId() )
4211  {
4212  case RndStdIds::FLY_AT_PAGE:
4213  // vertical: page | horizontal: page
4214  nP |= (1 << 4) | (2 << 6);
4215  break;
4216  // in case of Fly as characters: set paragraph-bound!!!
4217  case RndStdIds::FLY_AT_FLY:
4218  case RndStdIds::FLY_AT_CHAR:
4219  case RndStdIds::FLY_AT_PARA:
4220  case RndStdIds::FLY_AS_CHAR:
4221  // vertical: page | horizontal: page
4222  nP |= (2 << 4) | (0 << 6);
4223  break;
4224  default:
4225  break;
4226  }
4227 
4228  // sprmPPc
4229  m_rWW8Export.InsUInt16( NS_sprm::PPc::val );
4230  m_rWW8Export.pO->push_back( nP );
4231 }
4232 
4234 {
4235  // WW cannot have background in a section
4236  if ( m_rWW8Export.m_bOutPageDescs )
4237  return;
4238 
4239  WW8_SHD aSHD;
4240  WW8Export::TransBrush( rBrush.GetColor(), aSHD );
4241 
4242  m_rWW8Export.InsUInt16( NS_sprm::PShd80::val );
4243  m_rWW8Export.InsUInt16( aSHD.GetValue() );
4244 
4245  m_rWW8Export.InsUInt16( NS_sprm::PShd::val );
4246  m_rWW8Export.pO->push_back( 10 ); //size of operand: MUST be 10
4247  m_rWW8Export.InsUInt32( 0xFF000000 ); //cvFore: Foreground BGR = cvAuto
4248  m_rWW8Export.InsUInt32( SuitableBGColor( rBrush.GetColor() ) ); //cvBack
4249  m_rWW8Export.InsUInt16( 0x0000 ); //iPat: specifies the pattern used for shading = clear/100% background
4250 }
4251 
4253 {
4254  // WW cannot have background in a section
4255  if ( m_rWW8Export.m_bOutPageDescs )
4256  return;
4257 
4258  // see MSWordExportBase::OutputItemSet for how _SOLID is handled
4259  if ( rFillStyle.GetValue() != drawing::FillStyle_NONE )
4260  return;
4261 
4262  //Shd80Nil
4263  m_rWW8Export.InsUInt16( NS_sprm::PShd80::val );
4264  m_rWW8Export.InsUInt16( 0xffff );
4265 
4266  //cvAuto
4267  m_rWW8Export.InsUInt16( NS_sprm::PShd::val );
4268  m_rWW8Export.pO->push_back( 10 );
4269  m_rWW8Export.InsUInt32( 0xFF000000 );
4270  m_rWW8Export.InsUInt32( 0xFF000000 );
4271  m_rWW8Export.InsUInt16( 0x0000 );
4272 }
4273 
4275 {
4276 }
4277 
4278 WW8_BRCVer9 WW8Export::TranslateBorderLine(const SvxBorderLine& rLine,
4279  sal_uInt16 nDist, bool bShadow)
4280 {
4281  sal_uInt32 nColBGR = 0;
4282  sal_uInt16 nWidth = ::editeng::ConvertBorderWidthToWord(
4283  rLine.GetBorderLineStyle(), rLine.GetWidth());
4284  sal_uInt8 brcType = 0;
4285 
4286  if( nWidth ) // line ?
4287  {
4288  // BRC.brcType
4289  brcType = 0;
4290  // All the border types values are available on
4291  // http://msdn.microsoft.com/en-us/library/dd908142%28v=office.12%29.aspx
4292  switch (rLine.GetBorderLineStyle())
4293  {
4294  case SvxBorderLineStyle::SOLID:
4295  {
4296  if ( rLine.GetWidth( ) == DEF_LINE_WIDTH_0 )
4297  brcType = 5;
4298  else
4299  brcType = 1;
4300  }
4301  break;
4302  case SvxBorderLineStyle::DOTTED:
4303  brcType = 6;
4304  break;
4305  case SvxBorderLineStyle::DASHED:
4306  brcType = 7;
4307  break;
4308  case SvxBorderLineStyle::DOUBLE:
4309  case SvxBorderLineStyle::DOUBLE_THIN:
4310  brcType = 3;
4311  break;
4312  case SvxBorderLineStyle::THINTHICK_SMALLGAP:
4313  brcType = 11;
4314  break;
4315  case SvxBorderLineStyle::THINTHICK_MEDIUMGAP:
4316  brcType = 14;
4317  break;
4318  case SvxBorderLineStyle::THINTHICK_LARGEGAP:
4319  brcType = 17;
4320  break;
4321  case SvxBorderLineStyle::THICKTHIN_SMALLGAP:
4322  brcType = 12;
4323  break;
4324  case SvxBorderLineStyle::THICKTHIN_MEDIUMGAP:
4325  brcType = 15;
4326  break;
4327  case SvxBorderLineStyle::THICKTHIN_LARGEGAP:
4328  brcType = 18;
4329  break;
4330  case SvxBorderLineStyle::EMBOSSED:
4331  brcType = 24;
4332  break;
4333  case SvxBorderLineStyle::ENGRAVED:
4334  brcType = 25;
4335  break;
4336  case SvxBorderLineStyle::OUTSET:
4337  brcType = 26;
4338  break;
4339  case SvxBorderLineStyle::INSET:
4340  brcType = 27;
4341  break;
4342  case SvxBorderLineStyle::FINE_DASHED:
4343  brcType = 22;
4344  break;
4345  case SvxBorderLineStyle::DASH_DOT:
4346  brcType = 8;
4347  break;
4348  case SvxBorderLineStyle::DASH_DOT_DOT:
4349  brcType = 9;
4350  break;
4351  default:
4352  break;
4353  }
4354 
4355  // convert width from twips (1/20 pt) to eighths of a point
4356  nWidth = (( nWidth * 8 ) + 10 ) / 20;
4357  if( 0xff < nWidth )
4358  nWidth = 0xff;
4359 
4360  if( 0 == nWidth ) // really thin line
4361  nWidth = 1; // don't omit
4362 
4363  // BRC.cv
4364  nColBGR = wwUtility::RGBToBGR(rLine.GetColor().GetRGBColor());
4365  }
4366 
4367  // BRC.dptSpace
4368  sal_uInt16 nLDist = rtl::math::round(nDist / 20.0); // unit of measurement: pt
4369  if( nLDist > 0x1f )
4370  nLDist = 0x1f;
4371 
4372  return WW8_BRCVer9(nColBGR, sal_uInt8(nWidth), brcType, sal_uInt8(nLDist),
4373  bShadow, false);
4374 }
4375 
4382 void WW8Export::Out_BorderLine(ww::bytes& rO, const SvxBorderLine* pLine,
4383  sal_uInt16 nDist, sal_uInt16 nSprmNo, sal_uInt16 nSprmNoVer9, bool bShadow)
4384 {
4385  OSL_ENSURE( ( nSprmNo == 0 ) ||
4386  ( nSprmNo >= 38 && nSprmNo <= 41 ) ||
4387  ( nSprmNo >= NS_sprm::PBrcTop80::val
4388  && nSprmNo <= NS_sprm::PBrcRight80::val ) ||
4389  ( nSprmNo >= NS_sprm::SBrcTop80::val
4390  && nSprmNo <= NS_sprm::SBrcRight80::val ),
4391  "Sprm for border out is of range" );
4392 
4393  WW8_BRCVer9 aBrcVer9;
4394  WW8_BRC aBrcVer8;
4395 
4396  if( pLine && pLine->GetBorderLineStyle() != SvxBorderLineStyle::NONE )
4397  {
4398  aBrcVer9 = TranslateBorderLine( *pLine, nDist, bShadow );
4400  aBrcVer8 = WW8_BRC( aBrcVer9.dptLineWidth(), aBrcVer9.brcType(), ico,
4401  aBrcVer9.dptSpace(), aBrcVer9.fShadow(), aBrcVer9.fFrame() );
4402  }
4403 
4404  // WW97-SprmIds
4405  if ( nSprmNo != 0 )
4406  SwWW8Writer::InsUInt16( rO, nSprmNo );
4407 
4408  rO.insert( rO.end(), aBrcVer8.aBits1, aBrcVer8.aBits2+2 );
4409 
4410  if ( nSprmNoVer9 != 0 )
4411  {
4412  SwWW8Writer::InsUInt16( rO, nSprmNoVer9 );
4413  rO.push_back(sizeof(WW8_BRCVer9));
4414  rO.insert( rO.end(), aBrcVer9.aBits1, aBrcVer9.aBits2+4);
4415  }
4416 }
4417 
4424 void WW8Export::Out_SwFormatBox(const SvxBoxItem& rBox, bool bShadow)
4425 {
4426  static const SvxBoxItemLine aBorders[] =
4427  {
4428  SvxBoxItemLine::TOP, SvxBoxItemLine::LEFT, SvxBoxItemLine::BOTTOM, SvxBoxItemLine::RIGHT
4429  };
4430  static const sal_uInt16 aPBrc[] =
4431  {
4432  // WW8 SPRMs
4435  // WW9 SPRMs
4438  };
4439  static const sal_uInt16 aSBrc[] =
4440  {
4441  // WW8 SPRMs
4444  // WW9 SPRMs
4447  };
4448 
4449  const SvxBoxItemLine* pBrd = aBorders;
4450  for( sal_uInt16 i = 0; i < 4; ++i, ++pBrd )
4451  {
4452  const SvxBorderLine* pLn = rBox.GetLine( *pBrd );
4453 
4454  sal_uInt16 nSprmNo, nSprmNoVer9 = 0;
4455  if (m_bOutPageDescs)
4456  {
4457  nSprmNo = aSBrc[i];
4458  nSprmNoVer9 = aSBrc[i+4];
4459  }
4460  else
4461  {
4462  nSprmNo = aPBrc[i];
4463  nSprmNoVer9 = aPBrc[i+4];
4464  }
4465 
4466  Out_BorderLine( *pO, pLn, rBox.GetDistance( *pBrd ), nSprmNo,
4467  nSprmNoVer9, bShadow );
4468  }
4469 }
4470 
4480 {
4481  // possible and maybe better would be 0xffff
4482  static const SvxBoxItemLine aBorders[] =
4483  {
4484  SvxBoxItemLine::TOP, SvxBoxItemLine::LEFT, SvxBoxItemLine::BOTTOM, SvxBoxItemLine::RIGHT
4485  };
4486  static const SvxBorderLine aBorderLine;
4487 
4488  for(const SvxBoxItemLine & rBorder : aBorders)
4489  {
4490  const SvxBorderLine* pLn;
4491  if (pBox != nullptr)
4492  pLn = pBox->GetLine( rBorder );
4493  else
4494  pLn = & aBorderLine;
4495 
4496  Out_BorderLine(rO, pLn, 0, 0, 0, false);
4497  }
4498 }
4499 
4501  sal_uInt8 nLimit )
4502 {
4503  if ( !pBox )
4504  return;
4505 
4506  static const SvxBoxItemLine aBorders[] =
4507  {
4508  SvxBoxItemLine::TOP, SvxBoxItemLine::LEFT, SvxBoxItemLine::BOTTOM, SvxBoxItemLine::RIGHT
4509  };
4510 
4511  for( int i = 0; i < 4; ++i )
4512  {
4513  const SvxBorderLine* pLn = pBox->GetLine( aBorders[i] );
4514  if (!pLn)
4515  continue;
4516 
4517  InsUInt16( NS_sprm::TSetBrc::val );
4518  pO->push_back( 11 );
4519  pO->push_back( nStart );
4520  pO->push_back( nLimit );
4521  pO->push_back( 1<<i );
4522  WW8_BRCVer9 aBrcVer9 = TranslateBorderLine( *pLn, 0, false );
4523  pO->insert( pO->end(), aBrcVer9.aBits1, aBrcVer9.aBits2+4 );
4524  }
4525 }
4526 
4528 {
4529  // Fly around graphic -> here no border, because the
4530  // graphics header already has the border
4531  if ( m_rWW8Export.m_bOutGrf )
4532  return;
4533 
4534  bool bShadow = false;
4535  const SfxPoolItem* pItem = m_rWW8Export.HasItem( RES_SHADOW );
4536  if ( pItem )
4537  {
4538  const SvxShadowItem* p = static_cast<const SvxShadowItem*>(pItem);
4539  bShadow = ( p->GetLocation() != SvxShadowLocation::NONE )
4540  && ( p->GetWidth() != 0 );
4541  }
4542 
4543  SvxBoxItem aBox(rBox);
4544  if (m_rWW8Export.m_bOutPageDescs)
4545  {
4546  editeng::WordBorderDistances aDistances;
4547  editeng::BorderDistancesToWord(aBox, m_pageMargins, aDistances);
4548 
4549  aBox.SetDistance(aDistances.nTop, SvxBoxItemLine::TOP);
4550  aBox.SetDistance(aDistances.nLeft, SvxBoxItemLine::LEFT);
4551  aBox.SetDistance(aDistances.nBottom, SvxBoxItemLine::BOTTOM);
4552  aBox.SetDistance(aDistances.nRight, SvxBoxItemLine::RIGHT);
4553 
4554  m_bFromEdge = aDistances.bFromEdge;
4555  }
4556 
4557  m_rWW8Export.Out_SwFormatBox( aBox, bShadow );
4558 }
4559 
4561 {
4562  const SwFrameFormat* pFormat = m_pCurrentPageDesc ? &m_pCurrentPageDesc->GetMaster()
4563  : &m_rDoc.GetPageDesc(0).GetMaster();
4564 
4565  const SvxLRSpaceItem& rLR = pFormat->GetLRSpace();
4566  SwTwips nPageSize = pFormat->GetFrameSize().GetWidth();
4567  rLeft = rLR.GetLeft();
4568  rRight = rLR.GetRight();
4569  return nPageSize;
4570 }
4571 
4572 void WW8AttributeOutput::FormatColumns_Impl( sal_uInt16 nCols, const SwFormatCol & rCol, bool bEven, SwTwips nPageSize )
4573 {
4574  // CColumns
4575  m_rWW8Export.InsUInt16( NS_sprm::SCcolumns::val );
4576  m_rWW8Export.InsUInt16( nCols - 1 );
4577 
4578  // DxaColumns
4579  m_rWW8Export.InsUInt16( NS_sprm::SDxaColumns::val );
4580  m_rWW8Export.InsUInt16( rCol.GetGutterWidth( true ) );
4581 
4582  // LBetween
4583  m_rWW8Export.InsUInt16( NS_sprm::SLBetween::val );
4584  m_rWW8Export.pO->push_back( COLADJ_NONE == rCol.GetLineAdj( )? 0 : 1 );
4585 
4586  const SwColumns & rColumns = rCol.GetColumns( );
4587 
4588  // FEvenlySpaced
4589  m_rWW8Export.InsUInt16( NS_sprm::SFEvenlySpaced::val );
4590  m_rWW8Export.pO->push_back( bEven ? 1 : 0 );
4591 
4592  if ( bEven )
4593  return;
4594 
4595  for ( sal_uInt16 n = 0; n < nCols; ++n )
4596  {
4597  //sprmSDxaColWidth
4598  m_rWW8Export.InsUInt16( NS_sprm::SDxaColWidth::val );
4599  m_rWW8Export.pO->push_back( static_cast<sal_uInt8>(n) );
4600  m_rWW8Export.InsUInt16( rCol.
4601  CalcPrtColWidth( n,
4602  static_cast<sal_uInt16>(nPageSize) ) );
4603 
4604  if ( n + 1 != nCols )
4605  {
4606  //sprmSDxaColSpacing
4607  m_rWW8Export.InsUInt16( NS_sprm::SDxaColSpacing::val );
4608  m_rWW8Export.pO->push_back( static_cast<sal_uInt8>(n) );
4609  m_rWW8Export.InsUInt16( rColumns[n].GetRight( ) +
4610  rColumns[n + 1].GetLeft( ) );
4611  }
4612  }
4613 }
4614 
4616 {
4617  const SwColumns& rColumns = rCol.GetColumns();
4618 
4619  sal_uInt16 nCols = rColumns.size();
4620  if (1 >= nCols || GetExport( ).m_bOutFlyFrameAttrs)
4621  return;
4622 
4623  // get the page width without borders !!
4624 
4625  const SwFrameFormat* pFormat = GetExport( ).m_pCurrentPageDesc ? &GetExport( ).m_pCurrentPageDesc->GetMaster() : &const_cast<const SwDoc&>(GetExport().m_rDoc).GetPageDesc(0).GetMaster();
4626  const SvxFrameDirectionItem &frameDirection = pFormat->GetFrameDir();
4627  SwTwips nPageSize;
4628  if ( frameDirection.GetValue() == SvxFrameDirection::Vertical_RL_TB || frameDirection.GetValue() == SvxFrameDirection::Vertical_LR_TB )
4629  {
4630  const SvxULSpaceItem &rUL = pFormat->GetULSpace();
4631  nPageSize = pFormat->GetFrameSize().GetHeight();
4632  nPageSize -= rUL.GetUpper() + rUL.GetLower();
4633 
4634  const SwFormatHeader *header = pFormat->GetAttrSet().GetItem(RES_HEADER);
4635  if ( header )
4636  {
4637  const SwFrameFormat *headerFormat = header->GetHeaderFormat();
4638  if (headerFormat)
4639  {
4640  nPageSize -= headerFormat->GetFrameSize().GetHeight();
4641  }
4642  }
4643  const SwFormatFooter *footer = pFormat->GetAttrSet().GetItem(RES_FOOTER);
4644  if ( footer )
4645  {
4646  const SwFrameFormat *footerFormat = footer->GetFooterFormat();
4647  if ( footerFormat )
4648  {
4649  nPageSize -= footerFormat->GetFrameSize().GetHeight();
4650  }
4651  }
4652  }
4653  else
4654  {
4655  const SvxLRSpaceItem &rLR = pFormat->GetLRSpace();
4656  nPageSize = pFormat->GetFrameSize().GetWidth();
4657  nPageSize -= rLR.GetLeft() + rLR.GetRight();
4658  //i120133: The Section width should consider page indent value.
4659  nPageSize -= rCol.GetAdjustValue();
4660 
4661  }
4662 
4663  // look if all columns are equal
4664  bool bEven = true;
4665  sal_uInt16 n;
4666  sal_uInt16 nColWidth = rCol.CalcPrtColWidth( 0, static_cast<sal_uInt16>(nPageSize) );
4667  for ( n = 1; n < nCols; n++ )
4668  {
4669  short nDiff = nColWidth -
4670  rCol.CalcPrtColWidth( n, static_cast<sal_uInt16>(nPageSize) );
4671 
4672  if ( nDiff > 10 || nDiff < -10 ) // Tolerance: 10 tw
4673  {
4674  bEven = false;
4675  break;
4676  }
4677  }
4678 
4679  FormatColumns_Impl( nCols, rCol, bEven, nPageSize );
4680 }
4681 
4682 // "Paragraphs together"
4684 {
4685  // sprmFKeepFollow
4686  m_rWW8Export.InsUInt16( NS_sprm::PFKeepFollow::val );
4687 
4688  m_rWW8Export.pO->push_back( rKeep.GetValue() ? 1 : 0 );
4689 }
4690 
4691 // exclude a paragraph from Line Numbering
4693 {
4694  // sprmPFNoLineNumb
4695  m_rWW8Export.InsUInt16( NS_sprm::PFNoLineNumb::val );
4696 
4697  m_rWW8Export.pO->push_back( rNumbering.IsCount() ? 0 : 1 );
4698 }
4699 
4700 /* File PARATR.HXX */
4701 
4702 void WW8AttributeOutput::ParaLineSpacing_Impl( short nSpace, short nMulti )
4703 {
4704  // sprmPDyaLine
4705  m_rWW8Export.InsUInt16( NS_sprm::PDyaLine::val );
4706 
4707  m_rWW8Export.InsUInt16( nSpace );
4708  m_rWW8Export.InsUInt16( nMulti );
4709 }
4710 
4712 {
4713  short nSpace = 240, nMulti = 0;
4714 
4715  switch ( rSpacing.GetLineSpaceRule() )
4716  {
4717  default:
4718  break;
4719  case SvxLineSpaceRule::Fix: // Fix
4720  nSpace = -static_cast<short>(rSpacing.GetLineHeight());
4721  break;
4722  case SvxLineSpaceRule::Min: // At least
4723  nSpace = static_cast<short>(rSpacing.GetLineHeight());
4724  break;
4725  case SvxLineSpaceRule::Auto:
4726  {
4727  if( rSpacing.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Fix ) // Leading
4728  {
4729  // doesn't exist in WW - how do you get the MaxLineHeight?
4730  nSpace = rSpacing.GetInterLineSpace();
4731  sal_uInt16 nScript =
4732  i18n::ScriptType::LATIN;
4733  const SwAttrSet *pSet = nullptr;
4734  if ( auto pFormat = dynamic_cast< const SwFormat *>( GetExport().m_pOutFormatNode ) )
4735  {
4736  pSet = &pFormat->GetAttrSet();
4737  }
4738  else if ( auto pNd = dynamic_cast< const SwTextNode *>( GetExport().m_pOutFormatNode ) )
4739  {
4740  pSet = &pNd->GetSwAttrSet();
4741  nScript = g_pBreakIt->GetBreakIter()->getScriptType(pNd->GetText(), 0);
4742  }
4743  OSL_ENSURE( pSet, "No attrset for lineheight :-(" );
4744  if ( pSet )
4745  {
4746  nSpace = nSpace + static_cast<short>( AttrSetToLineHeight( GetExport().m_rDoc.getIDocumentSettingAccess(),
4747  *pSet, *Application::GetDefaultDevice(), nScript ) );
4748  }
4749  }
4750  else // Proportional
4751  {
4752  if ( rSpacing.GetInterLineSpaceRule() != SvxInterLineSpaceRule::Off )
4753  nSpace = static_cast<short>( ( 240L * rSpacing.GetPropLineSpace() ) / 100L );
4754  nMulti = 1;
4755  }
4756  }
4757  break;
4758  }
4759  // if nSpace is negative, it is a fixed size in 1/20 of a point
4760  // if nSpace is positive and nMulti is 1, it is 1/240 of a single line height
4761  // otherwise, it is a minimum size in 1/20 of a point
4762  ParaLineSpacing_Impl( nSpace, nMulti );
4763 }
4764 
4766 {
4767  // sprmPJc
4768  sal_uInt8 nAdj;
4769  sal_uInt8 nAdjBiDi;
4770  switch ( rAdjust.GetAdjust() )
4771  {
4772  case SvxAdjust::Left:
4773  nAdj = 0;
4774  nAdjBiDi = 2;
4775  break;
4776  case SvxAdjust::Right:
4777  nAdj = 2;
4778  nAdjBiDi = 0;
4779  break;
4780  case SvxAdjust::BlockLine:
4781  case SvxAdjust::Block:
4782  nAdj = nAdjBiDi = 3;
4783  break;
4784  case SvxAdjust::Center:
4785  nAdj = nAdjBiDi = 1;
4786  break;
4787  default:
4788  return; // not a supported Attribute
4789  }
4790 
4791  m_rWW8Export.InsUInt16(NS_sprm::PJc80::val);
4792  m_rWW8Export.pO->push_back(nAdj);
4793 
4794  /*
4795  Sadly for left to right paragraphs both these values are the same,
4796  for right to left paragraphs the bidi one is the reverse of the
4797  normal one.
4798  */
4799  m_rWW8Export.InsUInt16(NS_sprm::PJc::val); //bidi version ?
4800  bool bBiDiSwap = false;
4801  if (m_rWW8Export.m_pOutFormatNode)
4802  {
4803  SvxFrameDirection nDirection = SvxFrameDirection::Horizontal_LR_TB;
4804  if (auto pTN = dynamic_cast<const SwTextNode*>(m_rWW8Export.m_pOutFormatNode))
4805  {
4806  SwPosition aPos(*pTN);
4807  nDirection = m_rWW8Export.m_rDoc.GetTextDirection(aPos);
4808  }
4809  else if (auto pC = dynamic_cast<const SwTextFormatColl*>(m_rWW8Export.m_pOutFormatNode))
4810  {
4811  const SvxFrameDirectionItem &rItem =
4812  ItemGet<SvxFrameDirectionItem>(*pC, RES_FRAMEDIR);
4813  nDirection = rItem.GetValue();
4814  }
4815  if ( ( nDirection == SvxFrameDirection::Horizontal_RL_TB ) ||
4816  ( nDirection == SvxFrameDirection::Environment && AllSettings::GetLayoutRTL() ) )
4817  {
4818  bBiDiSwap = true;
4819  }
4820  }
4821 
4822  if (bBiDiSwap)
4823  m_rWW8Export.pO->push_back(nAdjBiDi);
4824  else
4825  m_rWW8Export.pO->push_back(nAdj);
4826 }
4827 
4829 {
4830  sal_uInt16 nTextFlow=0;
4831  bool bBiDi = false;
4832  SvxFrameDirection nDir = rDirection.GetValue();
4833 
4834  if ( nDir == SvxFrameDirection::Environment )
4835  nDir = GetExport( ).GetDefaultFrameDirection( );
4836 
4837 
4838  switch ( nDir )
4839  {
4840  default:
4841  //Can't get an unknown type here
4842  OSL_FAIL("Unknown frame direction");
4843  [[fallthrough]];
4844  case SvxFrameDirection::Horizontal_LR_TB:
4845  nTextFlow = 0;
4846  break;
4847  case SvxFrameDirection::Horizontal_RL_TB:
4848  nTextFlow = 0;
4849  bBiDi = true;
4850  break;
4851  case SvxFrameDirection::Vertical_LR_TB: //word doesn't have this
4852  case SvxFrameDirection::Vertical_RL_TB:
4853  nTextFlow = 1;
4854  break;
4855  }
4856 
4857  if ( m_rWW8Export.m_bOutPageDescs )
4858  {
4859  m_rWW8Export.InsUInt16( NS_sprm::STextFlow::val );
4860  m_rWW8Export.InsUInt16( nTextFlow );
4861  m_rWW8Export.InsUInt16( NS_sprm::SFBiDi::val );
4862  m_rWW8Export.pO->push_back( bBiDi ? 1 : 0 );
4863  }
4864  else if ( !m_rWW8Export.m_bOutFlyFrameAttrs ) //paragraph/style
4865  {
4866  m_rWW8Export.InsUInt16( NS_sprm::PFBiDi::val );
4867  m_rWW8Export.pO->push_back( bBiDi ? 1 : 0 );
4868  }
4869 }
4870 
4872 {
4873 }
4874 
4876 {
4877 }
4878 
4880 {
4881 }
4882 
4883 // "Separate paragraphs"
4885 {
4886  // sprmPFKeep
4887  m_rWW8Export.InsUInt16( NS_sprm::PFKeep::val );
4888  m_rWW8Export.pO->push_back( rSplit.GetValue() ? 0 : 1 );
4889 }
4890 
4897 {
4898  // sprmPFWidowControl
4899  m_rWW8Export.InsUInt16( NS_sprm::PFWidowControl::val );
4900  m_rWW8Export.pO->push_back( rWidows.GetValue() ? 1 : 0 );
4901 }
4902 
4903 namespace {
4904 
4905 class SwWW8WrTabu
4906 {
4907  std::unique_ptr<sal_uInt8[]> pDel; // DelArray
4908  std::unique_ptr<sal_uInt8[]> pAddPos; // AddPos-Array
4909  std::unique_ptr<sal_uInt8[]> pAddTyp; // AddTyp-Array
4910  sal_uInt16 nAdd; // number of tabs to be added
4911  sal_uInt16 nDel; // number of tabs to be deleted
4912 
4913  SwWW8WrTabu(const SwWW8WrTabu&) = delete;
4914  SwWW8WrTabu& operator=(const SwWW8WrTabu&) = delete;
4915 
4916 public:
4917  SwWW8WrTabu(sal_uInt16 nDelMax, sal_uInt16 nAddMax);
4918 
4919  void Add(const SvxTabStop &rTS, tools::Long nAdjustment);
4920  void Del(const SvxTabStop &rTS, tools::Long nAdjustment);
4921  void PutAll(WW8Export& rWW8Wrt);
4922 };
4923 
4924 }
4925 
4926 SwWW8WrTabu::SwWW8WrTabu(sal_uInt16 nDelMax, sal_uInt16 nAddMax)
4927  : nAdd(0), nDel(0)
4928 {
4929  if (nDelMax)
4930  pDel.reset( new sal_uInt8[nDelMax * 2] );
4931  pAddPos.reset( new sal_uInt8[nAddMax * 2] );
4932  pAddTyp.reset( new sal_uInt8[nAddMax] );
4933 }
4934 
4938 void SwWW8WrTabu::Add(const SvxTabStop & rTS, tools::Long nAdjustment)
4939 {
4940  // insert tab position
4941  ShortToSVBT16(msword_cast<sal_Int16>(rTS.GetTabPos() + nAdjustment),
4942  pAddPos.get() + (nAdd * 2));
4943 
4944  // insert tab type
4945  sal_uInt8 nPara = 0;
4946  switch (rTS.GetAdjustment())
4947  {
4948  case SvxTabAdjust::Right:
4949  nPara = 2;
4950  break;
4951  case SvxTabAdjust::Center:
4952  nPara = 1;
4953  break;
4954  case SvxTabAdjust::Decimal:
4955  /*
4956  There is nothing we can do btw the decimal separator has been
4957  customized, but if you think different remember that different
4958  locales have different separators, i.e. german is a , while english
4959  is a .
4960  */
4961  nPara = 3;
4962  break;
4963  default:
4964  break;
4965  }
4966 
4967  switch( rTS.GetFill() )
4968  {
4969  case '.': // dotted leader
4970  nPara |= 1 << 3;
4971  break;
4972  case '_': // Single line leader
4973  nPara |= 3 << 3;
4974  break;
4975  case '-': // hyphenated leader
4976  nPara |= 2 << 3;
4977  break;
4978  case '=': // heavy line leader
4979  nPara |= 4 << 3;
4980  break;
4981  }
4982 
4983  pAddTyp[nAdd] = nPara;
4984  ++nAdd;
4985 }
4986 
4990 void SwWW8WrTabu::Del(const SvxTabStop &rTS, tools::Long nAdjustment)
4991 {
4992  // insert tab position
4993  ShortToSVBT16(msword_cast<sal_Int16>(rTS.GetTabPos() + nAdjustment),
4994  pDel.get() + (nDel * 2));
4995  ++nDel;
4996 }
4997 
5001 void SwWW8WrTabu::PutAll(WW8Export& rWrt)
5002 {
5003  if (!nAdd && !nDel) //If it's a no-op
5004  return;
5005  OSL_ENSURE(nAdd <= 255, "more than 255 added tabstops?");
5006  OSL_ENSURE(nDel <= 255, "more than 244 removed tabstops?");
5007  if (nAdd > 255)
5008  nAdd = 255;
5009  if (nDel > 255)
5010  nDel = 255;
5011 
5012  sal_uInt16 nSiz = 2 * nDel + 3 * nAdd + 2;
5013  if (nSiz > 255)
5014  nSiz = 255;
5015 
5017  // insert cch
5018  rWrt.pO->push_back(msword_cast<sal_uInt8>(nSiz));
5019  // write DelArr
5020  rWrt.pO->push_back(msword_cast<sal_uInt8>(nDel));
5021  rWrt.OutSprmBytes(pDel.get(), nDel * 2);
5022  // write InsArr
5023  rWrt.pO->push_back(msword_cast<sal_uInt8>(nAdd));
5024  rWrt.OutSprmBytes(pAddPos.get(), 2 * nAdd); // AddPosArray
5025  rWrt.OutSprmBytes(pAddTyp.get(), nAdd); // AddTypArray
5026 }
5027 
5028 static void ParaTabStopAdd( WW8Export& rWrt,
5029  const SvxTabStopItem& rTStops,
5030  const tools::Long nLParaMgn )
5031 {
5032  SwWW8WrTabu aTab( 0, rTStops.Count());
5033 
5034  for( sal_uInt16 n = 0; n < rTStops.Count(); n++ )
5035  {
5036  const SvxTabStop& rTS = rTStops[n];
5037  // ignore default tabs
5038  if (SvxTabAdjust::Default != rTS.GetAdjustment())
5039  aTab.Add(rTS, nLParaMgn);
5040  }
5041  aTab.PutAll( rWrt );
5042 }
5043 
5044 static bool lcl_IsEqual(tools::Long nOneLeft, const SvxTabStop &rOne,
5045  tools::Long nTwoLeft, const SvxTabStop &rTwo)
5046 {
5047  return(
5048  nOneLeft == nTwoLeft &&
5049  rOne.GetAdjustment() == rTwo.GetAdjustment() &&
5050  rOne.GetDecimal() == rTwo.GetDecimal() &&
5051  rOne.GetFill() == rTwo.GetFill()
5052  );
5053 }
5054 
5055 static void ParaTabStopDelAdd( WW8Export& rWrt,
5056  const SvxTabStopItem& rTStyle,
5057  const tools::Long nLStypeMgn,
5058  const SvxTabStopItem& rTNew,
5059  const tools::Long nLParaMgn )
5060 {
5061  SwWW8WrTabu aTab(rTStyle.Count(), rTNew.Count());
5062 
5063  sal_uInt16 nO = 0; // rTStyle Index
5064  sal_uInt16 nN = 0; // rTNew Index
5065 
5066  do {
5067  const SvxTabStop* pTO;
5068  tools::Long nOP;
5069  if( nO < rTStyle.Count() ) // old not yet at the end?
5070  {
5071  pTO = &rTStyle[ nO ];
5072  nOP = pTO->GetTabPos() + nLStypeMgn;
5073  if( SvxTabAdjust::Default == pTO->GetAdjustment() )
5074  {
5075  nO++; // ignore default tab
5076  continue;
5077  }
5078  }
5079  else
5080  {
5081  pTO = nullptr;
5082  nOP = LONG_MAX;
5083  }
5084 
5085  const SvxTabStop* pTN;
5086  tools::Long nNP;
5087  if( nN < rTNew.Count() ) // new not yet at the end
5088  {
5089  pTN = &rTNew[ nN ];
5090  nNP = pTN->GetTabPos() + nLParaMgn;
5091  if( SvxTabAdjust::Default == pTN->GetAdjustment() )
5092  {
5093  nN++; // ignore default tab
5094  continue;
5095  }
5096  }
5097  else
5098  {
5099  pTN = nullptr;
5100  nNP = LONG_MAX;
5101  }
5102 
5103  if( nOP == LONG_MAX && nNP == LONG_MAX )
5104  break; // everything done
5105 
5106  if( nOP < nNP ) // next tab is old
5107  {
5108  assert(pTO);
5109  aTab.Del(*pTO, nLStypeMgn); // must be deleted
5110  nO++;
5111  }
5112  else if( nNP < nOP ) // next tab is new
5113  {
5114  assert(pTN);
5115  aTab.Add(*pTN, nLParaMgn); // must be inserted
5116  nN++;
5117  }
5118  else if (lcl_IsEqual(nOP, *pTO, nNP, *pTN)) // tabs are equal
5119  {
5120  nO++; // nothing to do
5121  nN++;
5122  }
5123  else // tabs same position, different type
5124  {
5125  aTab.Del(*pTO, nLStypeMgn); // delete old one
5126  aTab.Add(*pTN, nLParaMgn); // insert new one
5127  nO++;
5128  nN++;
5129  }
5130  } while( true );
5131 
5132  aTab.PutAll( rWrt );
5133 }
5134 
5136 {
5137  const bool bTabsRelativeToIndex = m_rWW8Export.m_pCurPam->GetDoc().getIDocumentSettingAccess().get( DocumentSettingId::TABS_RELATIVE_TO_INDENT );
5138 
5139  tools::Long nCurrentLeft = 0;
5140  if ( bTabsRelativeToIndex )
5141  {
5142  const SfxPoolItem* pLR = m_rWW8Export.HasItem( RES_LR_SPACE );
5143 
5144  if ( pLR != nullptr )
5145  nCurrentLeft = static_cast<const SvxLRSpaceItem*>(pLR)->GetTextLeft();
5146  }
5147 
5148  // #i100264#
5149  if ( m_rWW8Export.m_bStyDef &&
5150  m_rWW8Export.m_pCurrentStyle != nullptr &&
5151  m_rWW8Export.m_pCurrentStyle->DerivedFrom() != nullptr )
5152  {
5153  SvxTabStopItem aParentTabs( 0, 0, SvxTabAdjust::Default, RES_PARATR_TABSTOP );
5154  const SwFormat *pParentStyle = m_rWW8Export.m_pCurrentStyle->DerivedFrom();
5155  {
5156  if (const SvxTabStopItem* pParentTabs = pParentStyle->GetAttrSet().GetItem<SvxTabStopItem>(RES_PARATR_TABSTOP))
5157  {
5158  aParentTabs.Insert( pParentTabs );
5159  }
5160  }
5161 
5162  // #i120938# - consider left indentation of style and its parent style
5163  tools::Long nParentLeft = 0;
5164  if ( bTabsRelativeToIndex )
5165  {
5166  const SvxLRSpaceItem &rStyleLR = ItemGet<SvxLRSpaceItem>( pParentStyle->GetAttrSet(), RES_LR_SPACE );
5167  nParentLeft = rStyleLR.GetTextLeft();
5168  }
5169 
5170  ParaTabStopDelAdd( m_rWW8Export, aParentTabs, nParentLeft, rTabStops, nCurrentLeft );
5171  return;
5172  }
5173 
5174  const SvxTabStopItem* pStyleTabs = nullptr;
5176  {
5178  }
5179 
5180  if ( !pStyleTabs )
5181  {
5182  ParaTabStopAdd(m_rWW8Export, rTabStops, nCurrentLeft);
5183  }
5184  else
5185  {
5186  tools::Long nStyleLeft = 0;
5187  if ( bTabsRelativeToIndex )
5188  {
5189  const SvxLRSpaceItem &rStyleLR = ItemGet<SvxLRSpaceItem>(*m_rWW8Export.m_pStyAttr, RES_LR_SPACE);
5190  nStyleLeft = rStyleLR.GetTextLeft();
5191  }
5192 
5194  *pStyleTabs, nStyleLeft,
5195  rTabStops, nCurrentLeft);
5196  }
5197 }
5198 
5200 {
5201  // FIXME maybe use 'item_cast', like 'item_cast<SvxCharHiddenItem>( rHt )'?
5202  switch ( rHt.Which() )
5203  {
5204  case RES_CHRATR_CASEMAP:
5205  CharCaseMap( static_cast< const SvxCaseMapItem& >( rHt ) );
5206  break;
5207  case RES_CHRATR_COLOR:
5208  CharColor( static_cast< const SvxColorItem& >( rHt ) );
5209  break;
5210  case RES_CHRATR_CONTOUR:
5211  CharContour( static_cast< const SvxContourItem& >( rHt ) );
5212  break;
5213  case RES_CHRATR_CROSSEDOUT:
5214  CharCrossedOut( static_cast< const SvxCrossedOutItem& >( rHt ) );
5215  break;
5216  case RES_CHRATR_ESCAPEMENT:
5217  CharEscapement( static_cast< const SvxEscapementItem& >( rHt ) );
5218  break;
5219  case RES_CHRATR_FONT:
5220  CharFont( static_cast< const SvxFontItem& >( rHt ) );
5221  break;
5222  case RES_CHRATR_FONTSIZE:
5223  CharFontSize( static_cast< const SvxFontHeightItem& >( rHt ) );
5224  break;
5225  case RES_CHRATR_KERNING:
5226  CharKerning( static_cast< const SvxKerningItem& >( rHt ) );
5227  break;
5228  case RES_CHRATR_LANGUAGE:
5229  CharLanguage( static_cast< const SvxLanguageItem& >( rHt ) );
5230  break;
5231  case RES_CHRATR_POSTURE:
5232  CharPosture( static_cast< const SvxPostureItem& >( rHt ) );
5233  break;
5234  case RES_CHRATR_SHADOWED:
5235  CharShadow( static_cast< const SvxShadowedItem& >( rHt ) );
5236  break;
5237  case RES_CHRATR_UNDERLINE:
5238  CharUnderline( static_cast< const SvxUnderlineItem& >( rHt ) );
5239  break;
5240  case RES_CHRATR_WEIGHT:
5241  CharWeight( static_cast< const SvxWeightItem& >( rHt ) );
5242  break;
5243  case RES_CHRATR_AUTOKERN:
5244  CharAutoKern( static_cast< const SvxAutoKernItem& >( rHt ) );
5245  break;
5246  case RES_CHRATR_BLINK:
5247  CharAnimatedText( static_cast< const SvxBlinkItem& >( rHt ) );
5248  break;
5249  case RES_CHRATR_BACKGROUND:
5250  CharBackgroundBase( static_cast< const SvxBrushItem& >( rHt ) );
5251  break;
5252 
5253  case RES_CHRATR_CJK_FONT:
5254  CharFontCJK( static_cast< const SvxFontItem& >( rHt ) );
5255  break;
5257  CharFontSizeCJK( static_cast< const SvxFontHeightItem& >( rHt ) );
5258  break;
5260  CharLanguageCJK( static_cast< const SvxLanguageItem& >( rHt ) );
5261  break;
5263  CharPostureCJK( static_cast< const SvxPostureItem& >( rHt ) );
5264  break;
5265  case RES_CHRATR_CJK_WEIGHT:
5266  CharWeightCJK( static_cast< const SvxWeightItem& >( rHt ) );
5267  break;
5268 
5269  case RES_CHRATR_CTL_FONT:
5270  CharFontCTL( static_cast< const SvxFontItem& >( rHt ) );
5271  break;
5273  CharFontSizeCTL( static_cast< const SvxFontHeightItem& >( rHt ) );
5274  break;
5276  CharLanguageCTL( static_cast< const SvxLanguageItem& >( rHt ) );
5277  break;
5279  CharPostureCTL( static_cast< const SvxPostureItem& >( rHt ) );
5280  break;
5281  case RES_CHRATR_CTL_WEIGHT:
5282  CharWeightCTL( static_cast< const SvxWeightItem& >( rHt ) );
5283  break;
5284 
5285  case RES_CHRATR_ROTATE:
5286  CharRotate( static_cast< const SvxCharRotateItem& >( rHt ) );
5287  break;
5289  CharEmphasisMark( static_cast< const SvxEmphasisMarkItem& >( rHt ) );
5290  break;
5291  case RES_CHRATR_TWO_LINES:
5292  CharTwoLines( static_cast< const SvxTwoLinesItem& >( rHt ) );
5293  break;
5294  case RES_CHRATR_SCALEW:
5295  CharScaleWidth( static_cast< const SvxCharScaleWidthItem& >( rHt ) );
5296  break;
5297  case RES_CHRATR_RELIEF:
5298  CharRelief( static_cast< const SvxCharReliefItem& >( rHt ) );
5299  break;
5300  case RES_CHRATR_HIDDEN:
5301  CharHidden( static_cast< const SvxCharHiddenItem& >( rHt ) );
5302  break;
5303  case RES_CHRATR_BOX:
5304  FormatCharBorder( static_cast< const SvxBoxItem& >( rHt ) );
5305  break;
5306  case RES_CHRATR_HIGHLIGHT:
5307  CharHighlight( static_cast< const SvxBrushItem& >( rHt ) );
5308  break;
5309  case RES_CHRATR_BIDIRTL:
5310  CharBidiRTL( rHt );
5311  break;
5312  case RES_CHRATR_IDCTHINT:
5313  CharIdctHint( rHt );
5314  break;
5315  case RES_TXTATR_INETFMT:
5316  TextINetFormat( static_cast< const SwFormatINetFormat& >( rHt ) );
5317  break;
5318  case RES_TXTATR_CHARFMT:
5319  TextCharFormat( static_cast< const SwFormatCharFormat& >( rHt ) );
5320  break;
5321 
5322  case RES_TXTATR_FIELD:
5323  case RES_TXTATR_ANNOTATION:
5324  case RES_TXTATR_INPUTFIELD:
5325  TextField( static_cast< const SwFormatField& >( rHt ) );
5326  break;
5327 
5328  case RES_TXTATR_FLYCNT:
5329  TextFlyContent( static_cast< const SwFormatFlyCnt& >( rHt ) );
5330  break;
5331  case RES_TXTATR_FTN:
5332  TextFootnote( static_cast< const SwFormatFootnote& >( rHt ) );
5333  break;
5334 
5336  ParaLineSpacing( static_cast< const SvxLineSpacingItem& >( rHt ) );
5337  break;
5338  case RES_PARATR_ADJUST:
5339  ParaAdjust( static_cast< const SvxAdjustItem& >( rHt ) );
5340  break;
5341  case RES_PARATR_SPLIT:
5342  ParaSplit( static_cast< const SvxFormatSplitItem& >( rHt ) );
5343  break;
5344  case RES_PARATR_WIDOWS:
5345  ParaWidows( static_cast< const SvxWidowsItem& >( rHt ) );
5346  break;
5347  case RES_PARATR_TABSTOP:
5348  ParaTabStop( static_cast< const SvxTabStopItem& >( rHt ) );
5349  break;
5350  case RES_PARATR_HYPHENZONE:
5351  ParaHyphenZone( static_cast< const SvxHyphenZoneItem& >( rHt ) );
5352  break;
5353  case RES_PARATR_NUMRULE:
5354  ParaNumRule( static_cast< const SwNumRuleItem& >( rHt ) );
5355  break;
5357  ParaScriptSpace( static_cast< const SfxBoolItem& >( rHt ) );
5358  break;
5360  ParaHangingPunctuation( static_cast< const SfxBoolItem& >( rHt ) );
5361  break;
5363  ParaForbiddenRules( static_cast< const SfxBoolItem& >( rHt ) );
5364  break;
5365  case RES_PARATR_VERTALIGN:
5366  ParaVerticalAlign( static_cast< const SvxParaVertAlignItem& >( rHt ) );
5367  break;
5368  case RES_PARATR_SNAPTOGRID:
5369  ParaSnapToGrid( static_cast< const SvxParaGridItem& >( rHt ) );
5370  break;
5371 
5372  case RES_FRM_SIZE:
5373  FormatFrameSize( static_cast< const SwFormatFrameSize& >( rHt ) );
5374  break;
5375  case RES_PAPER_BIN:
5376  FormatPaperBin( static_cast< const SvxPaperBinItem& >( rHt ) );
5377  break;
5378  case RES_LR_SPACE:
5379  FormatLRSpace( static_cast< const SvxLRSpaceItem& >( rHt ) );
5380  break;
5381  case RES_UL_SPACE:
5382  FormatULSpace( static_cast< const SvxULSpaceItem& >( rHt ) );
5383  break;
5384  case RES_PAGEDESC:
5385  FormatPageDescription( static_cast< const SwFormatPageDesc& >( rHt ) );
5386  break;
5387  case RES_BREAK:
5388  FormatBreak( static_cast< const SvxFormatBreakItem& >( rHt ) );
5389  break;
5390  case RES_SURROUND:
5391  FormatSurround( static_cast< const SwFormatSurround& >( rHt ) );
5392  break;
5393  case RES_VERT_ORIENT:
5394  FormatVertOrientation( static_cast< const SwFormatVertOrient& >( rHt ) );
5395  break;
5396  case RES_HORI_ORIENT:
5397  FormatHorizOrientation( static_cast< const SwFormatHoriOrient& >( rHt ) );
5398  break;
5399  case RES_ANCHOR:
5400  FormatAnchor( static_cast< const SwFormatAnchor& >( rHt ) );
5401  break;
5402  case RES_BACKGROUND:
5403  FormatBackground( static_cast< const SvxBrushItem& >( rHt ) );
5404  break;
5405  case XATTR_FILLSTYLE:
5406  FormatFillStyle( static_cast< const XFillStyleItem& >( rHt ) );
5407  break;
5408  case XATTR_FILLGRADIENT:
5409  FormatFillGradient( static_cast< const XFillGradientItem& >( rHt ) );
5410  break;
5411  case RES_BOX:
5412  FormatBox( static_cast< const SvxBoxItem& >( rHt ) );
5413  break;
5414  case RES_COL:
5415  FormatColumns( static_cast< const SwFormatCol& >( rHt ) );
5416  break;
5417  case RES_KEEP:
5418  FormatKeep( static_cast< const SvxFormatKeepItem& >( rHt ) );
5419  break;
5420  case RES_TEXTGRID:
5421  FormatTextGrid( static_cast< const SwTextGridItem& >( rHt ) );
5422  break;
5423  case RES_LINENUMBER:
5424  FormatLineNumbering( static_cast< const SwFormatLineNumber& >( rHt ) );
5425  break;
5426  case RES_FRAMEDIR:
5427  FormatFrameDirection( static_cast< const SvxFrameDirectionItem& >( rHt ) );
5428  break;
5429  case RES_PARATR_GRABBAG:
5430  ParaGrabBag(static_cast<const SfxGrabBagItem&>(rHt));
5431  break;
5433  ParaOutlineLevel(static_cast<const SfxUInt16Item&>(rHt));
5434  break;
5435  case RES_CHRATR_GRABBAG:
5436  CharGrabBag(static_cast<const SfxGrabBagItem&>(rHt));
5437  break;
5438 
5439  default:
5440  SAL_INFO("sw.ww8", "Unhandled SfxPoolItem with id " << rHt.Which() );
5441  break;
5442  }
5443 }
5444 
5445 void AttributeOutputBase::OutputStyleItemSet( const SfxItemSet& rSet, bool bTestForDefault )
5446 {
5447  // based on OutputItemSet() from wrt_fn.cxx
5448 
5449  const SfxItemPool& rPool = *rSet.GetPool();
5450  const SfxItemSet* pSet = &rSet;
5451  if ( !pSet->Count() )
5452  {
5453  while ( nullptr != ( pSet = pSet->GetParent() ) && !pSet->Count() )
5454  ;
5455 
5456  if ( !pSet )
5457  return;
5458  }
5459