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