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