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