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