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