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