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