LibreOffice Module sw (master)  1
rtfattributeoutput.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 #include "rtfattributeoutput.hxx"
21 #include <memory>
22 #include <cstring>
23 #include "rtfsdrexport.hxx"
24 #include "writerwordglue.hxx"
25 #include "ww8par.hxx"
26 #include <fmtcntnt.hxx>
27 #include <rtl/tencinfo.h>
28 #include <sal/log.hxx>
29 #include <sot/exchange.hxx>
30 #include <svtools/rtfkeywd.hxx>
31 #include <editeng/fontitem.hxx>
32 #include <editeng/tstpitem.hxx>
33 #include <editeng/adjustitem.hxx>
34 #include <editeng/spltitem.hxx>
35 #include <editeng/widwitem.hxx>
36 #include <editeng/postitem.hxx>
37 #include <editeng/wghtitem.hxx>
38 #include <editeng/kernitem.hxx>
40 #include <editeng/cmapitem.hxx>
41 #include <editeng/wrlmitem.hxx>
42 #include <editeng/udlnitem.hxx>
43 #include <editeng/langitem.hxx>
45 #include <editeng/fhgtitem.hxx>
46 #include <editeng/colritem.hxx>
48 #include <editeng/contouritem.hxx>
49 #include <editeng/shdditem.hxx>
50 #include <editeng/autokernitem.hxx>
52 #include <editeng/twolinesitem.hxx>
57 #include <editeng/blinkitem.hxx>
59 #include <editeng/boxitem.hxx>
60 #include <editeng/brushitem.hxx>
61 #include <editeng/ulspitem.hxx>
62 #include <editeng/shaditem.hxx>
63 #include <editeng/keepitem.hxx>
64 #include <editeng/frmdiritem.hxx>
65 #include <editeng/opaqitem.hxx>
66 #include <svx/svdouno.hxx>
68 #include <sfx2/sfxbasemodel.hxx>
69 #include <svx/xfillit0.hxx>
70 #include <svx/xflgrit.hxx>
71 #include <docufld.hxx>
72 #include <fmtclds.hxx>
73 #include <fmtrowsplt.hxx>
74 #include <fmtline.hxx>
75 #include <fmtanchr.hxx>
76 #include <ftninfo.hxx>
77 #include <htmltbl.hxx>
78 #include <ndgrf.hxx>
79 #include <pagedesc.hxx>
80 #include <swmodule.hxx>
81 #include <txtftn.hxx>
82 #include <txtinet.hxx>
83 #include <grfatr.hxx>
84 #include <ndole.hxx>
85 #include <lineinfo.hxx>
86 #include <redline.hxx>
87 #include <rtf.hxx>
89 #include <vcl/cvtgrf.hxx>
90 #include <oox/mathml/export.hxx>
91 #include <com/sun/star/i18n/ScriptType.hpp>
92 #include <svl/grabbagitem.hxx>
93 #include <frmatr.hxx>
94 #include <swtable.hxx>
95 #include "rtfexport.hxx"
96 
97 using namespace ::com::sun::star;
98 using namespace sw::util;
99 
100 static OString OutTBLBorderLine(RtfExport const& rExport, const editeng::SvxBorderLine* pLine,
101  const char* pStr)
102 {
103  OStringBuffer aRet;
104  if (pLine && !pLine->isEmpty())
105  {
106  aRet.append(pStr);
107  // single line
108  switch (pLine->GetBorderLineStyle())
109  {
110  case SvxBorderLineStyle::SOLID:
111  {
112  if (DEF_LINE_WIDTH_0 == pLine->GetWidth())
113  aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRHAIR);
114  else
115  aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRS);
116  }
117  break;
118  case SvxBorderLineStyle::DOTTED:
119  aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRDOT);
120  break;
121  case SvxBorderLineStyle::DASHED:
122  aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRDASH);
123  break;
124  case SvxBorderLineStyle::DOUBLE:
125  case SvxBorderLineStyle::DOUBLE_THIN:
126  aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRDB);
127  break;
128  case SvxBorderLineStyle::THINTHICK_SMALLGAP:
130  break;
131  case SvxBorderLineStyle::THINTHICK_MEDIUMGAP:
133  break;
134  case SvxBorderLineStyle::THINTHICK_LARGEGAP:
136  break;
137  case SvxBorderLineStyle::THICKTHIN_SMALLGAP:
139  break;
140  case SvxBorderLineStyle::THICKTHIN_MEDIUMGAP:
142  break;
143  case SvxBorderLineStyle::THICKTHIN_LARGEGAP:
145  break;
146  case SvxBorderLineStyle::EMBOSSED:
148  break;
149  case SvxBorderLineStyle::ENGRAVED:
151  break;
152  case SvxBorderLineStyle::OUTSET:
154  break;
155  case SvxBorderLineStyle::INSET:
157  break;
158  case SvxBorderLineStyle::FINE_DASHED:
160  break;
161  case SvxBorderLineStyle::DASH_DOT:
163  break;
164  case SvxBorderLineStyle::DASH_DOT_DOT:
166  break;
167  case SvxBorderLineStyle::NONE:
168  default:
169  aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRNONE);
170  break;
171  }
172 
173  double const fConverted(
175  if (255 >= pLine->GetWidth()) // That value comes from RTF specs
176  {
177  aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRW).append(static_cast<sal_Int32>(fConverted));
178  }
179  else
180  {
181  // use \brdrth to double the value range...
183  aRet.append(static_cast<sal_Int32>(fConverted) / 2);
184  }
185 
186  aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRCF);
187  aRet.append(static_cast<sal_Int32>(rExport.GetColor(pLine->GetColor())));
188  }
189  return aRet.makeStringAndClear();
190 }
191 
192 static OString OutBorderLine(RtfExport const& rExport, const editeng::SvxBorderLine* pLine,
193  const char* pStr, sal_uInt16 nDist,
194  SvxShadowLocation eShadowLocation = SvxShadowLocation::NONE)
195 {
196  OStringBuffer aRet;
197  aRet.append(OutTBLBorderLine(rExport, pLine, pStr));
198  aRet.append(OOO_STRING_SVTOOLS_RTF_BRSP);
199  aRet.append(static_cast<sal_Int32>(nDist));
200  if (eShadowLocation == SvxShadowLocation::BottomRight)
201  aRet.append(LO_STRING_SVTOOLS_RTF_BRDRSH);
202  return aRet.makeStringAndClear();
203 }
204 
205 void RtfAttributeOutput::RTLAndCJKState(bool bIsRTL, sal_uInt16 nScript)
206 {
207  m_bIsRTL = bIsRTL;
208  m_nScript = nScript;
209  m_bControlLtrRtl = true;
210 }
211 
213 {
214  if (m_bIsBeforeFirstParagraph && m_rExport.m_nTextTyp != TXT_HDFT)
215  m_bIsBeforeFirstParagraph = false;
216 
217  // Output table/table row/table cell starts if needed
218  if (pTextNodeInfo)
219  {
220  sal_uInt32 nRow = pTextNodeInfo->getRow();
221  sal_uInt32 nCell = pTextNodeInfo->getCell();
222 
223  // New cell/row?
224  if (m_nTableDepth > 0 && !m_bTableCellOpen)
225  {
227  pTextNodeInfo->getInnerForDepth(m_nTableDepth));
228  OSL_ENSURE(pDeepInner, "TableNodeInfoInner not found");
229  // Make sure we always start a row between ending one and starting a cell.
230  // In case of subtables, we may not get the first cell.
231  if (pDeepInner && (pDeepInner->getCell() == 0 || m_bTableRowEnded))
232  {
233  StartTableRow(pDeepInner);
234  }
235 
236  StartTableCell();
237  }
238 
239  // Again, if depth was incremented, start a new table even if we skipped the first cell.
240  if ((nRow == 0 && nCell == 0) || (m_nTableDepth == 0 && pTextNodeInfo->getDepth()))
241  {
242  // Do we have to start the table?
243  // [If we are at the right depth already, it means that we
244  // continue the table cell]
245  sal_uInt32 nCurrentDepth = pTextNodeInfo->getDepth();
246 
247  if (nCurrentDepth > m_nTableDepth)
248  {
249  // Start all the tables that begin here
250  for (sal_uInt32 nDepth = m_nTableDepth + 1; nDepth <= pTextNodeInfo->getDepth();
251  ++nDepth)
252  {
254  pTextNodeInfo->getInnerForDepth(nDepth));
255 
256  m_bLastTable = (nDepth == pTextNodeInfo->getDepth());
257  StartTable();
258  StartTableRow(pInner);
259  StartTableCell();
260  }
261 
262  m_nTableDepth = nCurrentDepth;
263  }
264  }
265  }
266 
267  OSL_ENSURE(m_aRun.getLength() == 0, "m_aRun is not empty");
268 }
269 
271 {
272  bool bLastPara = false;
273  if (m_rExport.m_nTextTyp == TXT_FTN || m_rExport.m_nTextTyp == TXT_EDN
274  || m_rExport.m_pDoc->IsClipBoard())
275  {
276  // We're ending a paragraph that is the last paragraph of a footnote or endnote, or of clipboard.
277  bLastPara
278  = m_rExport.GetCurrentNodeIndex()
279  && m_rExport.GetCurrentNodeIndex() == m_rExport.m_pCurPam->End()->nNode.GetIndex();
280  }
281 
282  FinishTableRowCell(pTextNodeInfoInner);
283 
284  RtfStringBuffer aParagraph;
285 
286  aParagraph.appendAndClear(m_aRun);
287  aParagraph->append(m_aAfterRuns.makeStringAndClear());
288  if (m_bTableAfterCell)
289  m_bTableAfterCell = false;
290  else
291  {
292  aParagraph->append(SAL_NEWLINE_STRING);
293  // RTF_PAR at the end of the footnote or clipboard, would cause an additional empty paragraph.
294  if (!bLastPara)
295  {
296  aParagraph->append(OOO_STRING_SVTOOLS_RTF_PAR);
297  aParagraph->append(' ');
298  }
299  }
300  if (m_nColBreakNeeded)
301  {
303  m_nColBreakNeeded = false;
304  }
305 
306  if (!m_bBufferSectionHeaders)
307  aParagraph.makeStringAndClear(this);
308  else
309  m_aSectionHeaders.append(aParagraph.makeStringAndClear());
310 }
311 
313 {
314  m_rExport.Strm()
315  .WriteCharPtr(SAL_NEWLINE_STRING)
316  .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PAR)
317  .WriteChar(' ');
318 }
319 
321 {
322  SwNodeIndex aNextIndex(rNode, 1);
323  if (rNode.IsTextNode())
324  {
325  OSL_ENSURE(m_aStyles.getLength() == 0, "m_aStyles is not empty");
326 
327  // output page/section breaks
328  m_rExport.Strm().WriteOString(m_aSectionBreaks.makeStringAndClear());
329  m_bBufferSectionBreaks = true;
330 
331  // output section headers / footers
332  if (!m_bBufferSectionHeaders)
333  m_rExport.Strm().WriteOString(m_aSectionHeaders.makeStringAndClear());
334 
335  if (aNextIndex.GetNode().IsTextNode())
336  {
337  const SwTextNode* pTextNode = static_cast<SwTextNode*>(&aNextIndex.GetNode());
338  m_rExport.OutputSectionBreaks(pTextNode->GetpSwAttrSet(), *pTextNode);
339  // Save the current page description for now, so later we will be able to access the previous one.
340  m_pPrevPageDesc = pTextNode->FindPageDesc();
341  }
342  else if (aNextIndex.GetNode().IsTableNode())
343  {
344  const SwTableNode* pTableNode = static_cast<SwTableNode*>(&aNextIndex.GetNode());
345  const SwFrameFormat* pFormat = pTableNode->GetTable().GetFrameFormat();
346  m_rExport.OutputSectionBreaks(&(pFormat->GetAttrSet()), *pTableNode);
347  }
348  m_bBufferSectionBreaks = false;
349  }
350  else if (rNode.IsEndNode())
351  {
352  // End of something: make sure that it's the end of a table.
353  assert(rNode.StartOfSectionNode()->IsTableNode());
354  if (aNextIndex.GetNode().IsTextNode())
355  {
356  // Handle section break between a table and a text node following it.
357  const SwTextNode* pTextNode = aNextIndex.GetNode().GetTextNode();
358  m_rExport.OutputSectionBreaks(pTextNode->GetpSwAttrSet(), *pTextNode);
359  }
360  }
361 }
362 
364 {
365  OStringBuffer aPar;
366  if (!m_rExport.GetRTFFlySyntax())
367  {
368  aPar.append(OOO_STRING_SVTOOLS_RTF_PARD);
369  aPar.append(OOO_STRING_SVTOOLS_RTF_PLAIN);
370  aPar.append(' ');
371  }
372  if (!m_bBufferSectionHeaders)
373  m_rExport.Strm().WriteOString(aPar.makeStringAndClear());
374  else
375  m_aSectionHeaders.append(aPar.makeStringAndClear());
376 }
377 
379  const SfxItemSet& /*rParagraphMarkerProperties*/, const SwRedlineData* /*pRedlineData*/,
380  const SwRedlineData* /*pRedlineParagraphMarkerDeleted*/,
381  const SwRedlineData* /*pRedlineParagraphMarkerInserted*/)
382 {
383  const OString aProperties = MoveCharacterProperties(true);
384  m_rExport.Strm().WriteOString(aProperties);
385 }
386 
387 void RtfAttributeOutput::StartRun(const SwRedlineData* pRedlineData, sal_Int32 /*nPos*/,
388  bool bSingleEmptyRun)
389 {
390  SAL_INFO("sw.rtf", OSL_THIS_FUNC << ", bSingleEmptyRun: " << bSingleEmptyRun);
391 
392  m_bInRun = true;
393  m_bSingleEmptyRun = bSingleEmptyRun;
394  if (!m_bSingleEmptyRun)
395  m_aRun->append('{');
396 
397  // if there is some redlining in the document, output it
398  Redline(pRedlineData);
399 
400  OSL_ENSURE(m_aRunText.getLength() == 0, "m_aRunText is not empty");
401 }
402 
403 void RtfAttributeOutput::EndRun(const SwTextNode* /*pNode*/, sal_Int32 /*nPos*/, bool /*bLastRun*/)
404 {
405  m_aRun->append(SAL_NEWLINE_STRING);
406  m_aRun.appendAndClear(m_aRunText);
407  if (!m_bSingleEmptyRun && m_bInRun)
408  m_aRun->append('}');
409  m_bInRun = false;
410 }
411 
413 {
414  OSL_ENSURE(m_aStyles.getLength() == 0, "m_aStyles is not empty");
415 }
416 
418 {
419  const OString aProperties = MoveCharacterProperties(true);
420  m_aRun->append(aProperties.getStr());
421 }
422 
423 OString RtfAttributeOutput::MoveCharacterProperties(bool aAutoWriteRtlLtr)
424 {
425  const OString aAssoc = m_aStylesAssoc.makeStringAndClear();
426  const OString aNormal = m_aStyles.makeStringAndClear();
427  OStringBuffer aBuf;
428 
429  if (aAutoWriteRtlLtr && !m_bControlLtrRtl)
430  {
431  m_bControlLtrRtl = !aAssoc.isEmpty();
432  m_bIsRTL = false;
433  m_nScript = i18n::ScriptType::LATIN;
434  }
435 
436  if (m_bControlLtrRtl)
437  {
438  m_bControlLtrRtl = false;
439 
440  /*
441  You would have thought that
442  m_rExport.Strm() << (bIsRTL ? OOO_STRING_SVTOOLS_RTF_RTLCH : OOO_STRING_SVTOOLS_RTF_LTRCH); would be sufficient here ,
443  but looks like word needs to see the other directional token to be
444  satisfied that all is kosher, otherwise it seems in ver 2003 to go and
445  semi-randomly stick strike through about the place. Perhaps
446  strikethrough is some ms developers "something is wrong signal" debugging
447  code that we're triggering ?
448  */
449  if (!aAssoc.isEmpty() || !aNormal.isEmpty())
450  {
451  if (m_bIsRTL)
452  {
453  aBuf.append(OOO_STRING_SVTOOLS_RTF_LTRCH)
454  .append(aAssoc)
455  .append(' ')
457  .append(aNormal);
458  }
459  else
460  {
461  aBuf.append(OOO_STRING_SVTOOLS_RTF_RTLCH)
462  .append(aAssoc)
463  .append(' ')
465  .append(aNormal);
466  }
467  }
468 
469  switch (m_nScript)
470  {
471  case i18n::ScriptType::LATIN:
472  aBuf.append(OOO_STRING_SVTOOLS_RTF_LOCH);
473  break;
474  case i18n::ScriptType::ASIAN:
475  aBuf.append(OOO_STRING_SVTOOLS_RTF_DBCH);
476  break;
477  case i18n::ScriptType::COMPLEX:
478  /* noop */
479  default:
480  /* should not happen? */
481  break;
482  }
483  }
484  else
485  {
486  aBuf.append(aAssoc).append(aNormal);
487  }
488 
489  return aBuf.makeStringAndClear();
490 }
491 
492 void RtfAttributeOutput::RunText(const OUString& rText, rtl_TextEncoding /*eCharSet*/)
493 {
494  SAL_INFO("sw.rtf", OSL_THIS_FUNC << ", rText: " << rText);
495  RawText(rText, m_rExport.GetCurrentEncoding());
496 }
497 
498 OStringBuffer& RtfAttributeOutput::RunText() { return m_aRunText.getLastBuffer(); }
499 
500 void RtfAttributeOutput::RawText(const OUString& rText, rtl_TextEncoding eCharSet)
501 {
502  m_aRunText->append(msfilter::rtfutil::OutString(rText, eCharSet));
503 }
504 
505 void RtfAttributeOutput::StartRuby(const SwTextNode& rNode, sal_Int32 nPos,
506  const SwFormatRuby& rRuby)
507 {
508  WW8Ruby aWW8Ruby(rNode, rRuby, GetExport());
509  OUString aStr(FieldString(ww::eEQ) + "\\* jc");
510  aStr += OUString::number(aWW8Ruby.GetJC()) + " \\* \"Font:";
511  aStr += aWW8Ruby.GetFontFamily() + "\" \\* hps";
512  aStr += OUString::number((aWW8Ruby.GetRubyHeight() + 5) / 10) + " \\o";
513  if (aWW8Ruby.GetDirective())
514  {
515  aStr += "\\a" + OUStringChar(aWW8Ruby.GetDirective());
516  }
517  aStr += "(\\s\\up " + OUString::number((aWW8Ruby.GetBaseHeight() + 10) / 20 - 1) + "(";
518  EndRun(&rNode, nPos);
519  m_rExport.OutputField(nullptr, ww::eEQ, aStr, FieldFlags::Start | FieldFlags::CmdStart);
520  aStr = rRuby.GetText() + "),";
521  m_rExport.OutputField(nullptr, ww::eEQ, aStr, FieldFlags::NONE);
522 }
523 
524 void RtfAttributeOutput::EndRuby(const SwTextNode& rNode, sal_Int32 nPos)
525 {
526  m_rExport.OutputField(nullptr, ww::eEQ, ")",
528  EndRun(&rNode, nPos);
529 }
530 
531 bool RtfAttributeOutput::StartURL(const OUString& rUrl, const OUString& rTarget)
532 {
533  m_sURL = rUrl;
534  // Ignore hyperlink without a URL.
535  if (!rUrl.isEmpty())
536  {
537  m_aRun->append('{');
538  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FIELD);
539  m_aRun->append('{');
540  m_aRun->append(OOO_STRING_SVTOOLS_RTF_IGNORE);
541  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FLDINST);
542  m_aRun->append(" HYPERLINK ");
543 
544  m_aRun->append("\"");
545  m_aRun->append(msfilter::rtfutil::OutString(rUrl, m_rExport.GetCurrentEncoding()));
546  m_aRun->append("\" ");
547 
548  if (!rTarget.isEmpty())
549  {
550  m_aRun->append("\\\\t \"");
551  m_aRun->append(msfilter::rtfutil::OutString(rTarget, m_rExport.GetCurrentEncoding()));
552  m_aRun->append("\" ");
553  }
554 
555  m_aRun->append("}");
556  m_aRun->append("{" OOO_STRING_SVTOOLS_RTF_FLDRSLT " {");
557  }
558  return true;
559 }
560 
561 bool RtfAttributeOutput::EndURL(bool const isAtEndOfParagraph)
562 {
563  if (!m_sURL.isEmpty())
564  {
565  // UGLY: usually EndRun is called earlier, but there is an extra
566  // call to OutAttrWithRange() when at the end of the paragraph,
567  // so in that special case the output needs to be appended to the
568  // new run's text instead of the previous run
569  if (isAtEndOfParagraph)
570  {
571  // close the fldrslt group
572  m_aRunText->append("}}");
573  // close the field group
574  m_aRunText->append('}');
575  }
576  else
577  {
578  // close the fldrslt group
579  m_aRun->append("}}");
580  // close the field group
581  m_aRun->append('}');
582  }
583  m_sURL.clear();
584  }
585  return true;
586 }
587 
588 void RtfAttributeOutput::FieldVanish(const OUString& /*rText*/, ww::eField /*eType*/)
589 {
590  SAL_INFO("sw.rtf", "TODO: " << OSL_THIS_FUNC);
591 }
592 
594 {
595  if (!pRedline)
596  return;
597 
598  if (pRedline->GetType() == RedlineType::Insert)
599  {
600  m_aRun->append(OOO_STRING_SVTOOLS_RTF_REVISED);
601  m_aRun->append(OOO_STRING_SVTOOLS_RTF_REVAUTH);
602  m_aRun->append(static_cast<sal_Int32>(
603  m_rExport.GetRedline(SW_MOD()->GetRedlineAuthor(pRedline->GetAuthor()))));
604  m_aRun->append(OOO_STRING_SVTOOLS_RTF_REVDTTM);
605  }
606  else if (pRedline->GetType() == RedlineType::Delete)
607  {
608  m_aRun->append(OOO_STRING_SVTOOLS_RTF_DELETED);
609  m_aRun->append(OOO_STRING_SVTOOLS_RTF_REVAUTHDEL);
610  m_aRun->append(static_cast<sal_Int32>(
611  m_rExport.GetRedline(SW_MOD()->GetRedlineAuthor(pRedline->GetAuthor()))));
612  m_aRun->append(OOO_STRING_SVTOOLS_RTF_REVDTTMDEL);
613  }
614  m_aRun->append(static_cast<sal_Int32>(sw::ms::DateTime2DTTM(pRedline->GetTimeStamp())));
615  m_aRun->append(' ');
616 }
617 
619  const SwFormatDrop& /*rSwFormatDrop*/, sal_uInt16 /*nStyle*/,
620  ww8::WW8TableNodeInfo::Pointer_t /*pTextNodeInfo*/,
621  ww8::WW8TableNodeInfoInner::Pointer_t /*pTextNodeInfoInner*/)
622 {
623  SAL_INFO("sw.rtf", "TODO: " << OSL_THIS_FUNC);
624 }
625 
626 void RtfAttributeOutput::ParagraphStyle(sal_uInt16 nStyle)
627 {
628  OString* pStyle = m_rExport.GetStyle(nStyle);
629  OStringBuffer aStyle;
630  aStyle.append(OOO_STRING_SVTOOLS_RTF_S);
631  aStyle.append(static_cast<sal_Int32>(nStyle));
632  if (pStyle)
633  aStyle.append(pStyle->getStr());
634  if (!m_bBufferSectionHeaders)
635  m_rExport.Strm().WriteOString(aStyle.makeStringAndClear());
636  else
637  m_aSectionHeaders.append(aStyle.makeStringAndClear());
638 }
639 
641  ww8::WW8TableNodeInfoInner::Pointer_t /*pTableTextNodeInfoInner*/)
642 {
643  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_INTBL);
644  if (m_nTableDepth > 1)
645  {
646  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ITAP);
647  m_aStyles.append(static_cast<sal_Int32>(m_nTableDepth));
648  }
649  m_bWroteCellInfo = true;
650 }
651 
653 {
654  /* noop */
655 }
656 
658  ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)
659 {
660  InitTableHelper(pTableTextNodeInfoInner);
661 
662  const SwTable* pTable = pTableTextNodeInfoInner->getTable();
663  SwFrameFormat* pFormat = pTable->GetFrameFormat();
664 
665  m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_TROWD);
666  TableOrientation(pTableTextNodeInfoInner);
667  TableBidi(pTableTextNodeInfoInner);
668  TableHeight(pTableTextNodeInfoInner);
669  TableCanSplit(pTableTextNodeInfoInner);
670 
671  // Cell margins
672  const SvxBoxItem& rBox = pFormat->GetBox();
673  static const SvxBoxItemLine aBorders[] = { SvxBoxItemLine::TOP, SvxBoxItemLine::LEFT,
674  SvxBoxItemLine::BOTTOM, SvxBoxItemLine::RIGHT };
675 
676  static const char* aRowPadNames[]
679 
680  static const char* aRowPadUnits[]
683 
684  for (int i = 0; i < 4; ++i)
685  {
686  m_aRowDefs.append(aRowPadUnits[i]);
687  m_aRowDefs.append(sal_Int32(3));
688  m_aRowDefs.append(aRowPadNames[i]);
689  m_aRowDefs.append(static_cast<sal_Int32>(rBox.GetDistance(aBorders[i])));
690  }
691 
692  // The cell-dependent properties
693  const double fWidthRatio = m_pTableWrt->GetAbsWidthRatio();
694  const SwWriteTableRows& aRows = m_pTableWrt->GetRows();
695  SwWriteTableRow* pRow = aRows[pTableTextNodeInfoInner->getRow()].get();
696  SwTwips nSz = 0;
697 
698  // Not using m_nTableDepth, which is not yet incremented here.
699  sal_uInt32 nCurrentDepth = pTableTextNodeInfoInner->getDepth();
700  m_aCells[nCurrentDepth] = pRow->GetCells().size();
701  for (sal_uInt32 i = 0; i < m_aCells[nCurrentDepth]; i++)
702  {
703  const SwWriteTableCell* const pCell = pRow->GetCells()[i].get();
704  const SwFrameFormat* pCellFormat = pCell->GetBox()->GetFrameFormat();
705 
706  pTableTextNodeInfoInner->setCell(i);
707  TableCellProperties(pTableTextNodeInfoInner);
708 
709  // Right boundary: this can't be in TableCellProperties as the old
710  // value of nSz is needed.
711  nSz += pCellFormat->GetFrameSize().GetWidth();
712  m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CELLX);
713  m_aRowDefs.append(static_cast<sal_Int32>(pFormat->GetLRSpace().GetLeft()
714  + rtl::math::round(nSz * fWidthRatio)));
715  }
716 }
717 
719  ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)
720 {
721  /*
722  * The function name is a bit misleading: given that we write borders
723  * before each row, we just have borders, not default ones. Additionally,
724  * this function actually writes borders for a specific cell only and is
725  * called for each cell.
726  */
727 
728  const SwWriteTableRows& aRows = m_pTableWrt->GetRows();
729  SwWriteTableRow* pRow = aRows[pTableTextNodeInfoInner->getRow()].get();
730  const SwWriteTableCell* const pCell
731  = pRow->GetCells()[pTableTextNodeInfoInner->getCell()].get();
732  const SwFrameFormat* pCellFormat = pCell->GetBox()->GetFrameFormat();
733  const SfxPoolItem* pItem;
734  if (pCellFormat->GetAttrSet().HasItem(RES_BOX, &pItem))
735  {
736  auto& rBox = static_cast<const SvxBoxItem&>(*pItem);
737  static const SvxBoxItemLine aBorders[] = { SvxBoxItemLine::TOP, SvxBoxItemLine::LEFT,
738  SvxBoxItemLine::BOTTOM, SvxBoxItemLine::RIGHT };
739  static const char* aBorderNames[]
742  //Yes left and top are swapped with each other for cell padding! Because
743  //that's what the thundering annoying rtf export/import word xp does.
744  static const char* aCellPadNames[]
747  static const char* aCellPadUnits[]
750  for (int i = 0; i < 4; ++i)
751  {
752  if (const editeng::SvxBorderLine* pLn = rBox.GetLine(aBorders[i]))
753  m_aRowDefs.append(OutTBLBorderLine(m_rExport, pLn, aBorderNames[i]));
754  if (rBox.GetDistance(aBorders[i]))
755  {
756  m_aRowDefs.append(aCellPadUnits[i]);
757  m_aRowDefs.append(sal_Int32(3));
758  m_aRowDefs.append(aCellPadNames[i]);
759  m_aRowDefs.append(static_cast<sal_Int32>(rBox.GetDistance(aBorders[i])));
760  }
761  }
762  }
763 }
764 
766  ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)
767 {
768  const SwTable* pTable = pTableTextNodeInfoInner->getTable();
769  const SwTableBox* pTableBox = pTableTextNodeInfoInner->getTableBox();
770  const SwTableLine* pTableLine = pTableBox->GetUpper();
771 
772  Color aColor = COL_AUTO;
773  auto pTableColorProp
775  if (pTableColorProp)
776  aColor = pTableColorProp->GetColor();
777 
778  auto pRowColorProp
780  if (pRowColorProp && pRowColorProp->GetColor() != COL_AUTO)
781  aColor = pRowColorProp->GetColor();
782 
783  const SwWriteTableRows& aRows = m_pTableWrt->GetRows();
784  SwWriteTableRow* pRow = aRows[pTableTextNodeInfoInner->getRow()].get();
785  const SwWriteTableCell* const pCell
786  = pRow->GetCells()[pTableTextNodeInfoInner->getCell()].get();
787  const SwFrameFormat* pCellFormat = pCell->GetBox()->GetFrameFormat();
788  const SfxPoolItem* pItem;
789  if (pCellFormat->GetAttrSet().HasItem(RES_BACKGROUND, &pItem))
790  {
791  auto& rBack = static_cast<const SvxBrushItem&>(*pItem);
792  if (rBack.GetColor() != COL_AUTO)
793  aColor = rBack.GetColor();
794  }
795 
796  if (!aColor.GetTransparency())
797  {
798  m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CLCBPAT);
799  m_aRowDefs.append(static_cast<sal_Int32>(m_rExport.GetColor(aColor)));
800  }
801 }
802 
804  ww8::WW8TableNodeInfoInner::Pointer_t /*pTableTextNodeInfoInner*/)
805 {
806 }
807 
809  ww8::WW8TableNodeInfoInner::Pointer_t /*pTableTextNodeInfoInner*/)
810 {
811 }
812 
814 {
815  const SwTableBox* pTabBox = pTableTextNodeInfoInner->getTableBox();
816  const SwTableLine* pTabLine = pTabBox->GetUpper();
817  const SwFrameFormat* pLineFormat = pTabLine->GetFrameFormat();
818  const SwFormatFrameSize& rLSz = pLineFormat->GetFrameSize();
819 
820  if (SwFrameSize::Variable != rLSz.GetHeightSizeType() && rLSz.GetHeight())
821  {
822  sal_Int32 nHeight = 0;
823 
824  switch (rLSz.GetHeightSizeType())
825  {
826  case SwFrameSize::Fixed:
827  nHeight = -rLSz.GetHeight();
828  break;
830  nHeight = rLSz.GetHeight();
831  break;
832  default:
833  break;
834  }
835 
836  if (nHeight)
837  {
838  m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_TRRH);
839  m_aRowDefs.append(nHeight);
840  }
841  }
842 }
843 
845  ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)
846 {
847  const SwTableBox* pTabBox = pTableTextNodeInfoInner->getTableBox();
848  const SwTableLine* pTabLine = pTabBox->GetUpper();
849  const SwFrameFormat* pLineFormat = pTabLine->GetFrameFormat();
850  const SwFormatRowSplit& rSplittable = pLineFormat->GetRowSplit();
851 
852  // The rtf default is to allow a row to break
853  if (!rSplittable.GetValue())
854  m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_TRKEEP);
855 }
856 
858 {
859  const SwTable* pTable = pTableTextNodeInfoInner->getTable();
860  const SwFrameFormat* pFrameFormat = pTable->GetFrameFormat();
861 
862  if (m_rExport.TrueFrameDirection(*pFrameFormat) != SvxFrameDirection::Horizontal_RL_TB)
863  m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_LTRROW);
864  else
865  m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_RTLROW);
866 }
867 
869  ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)
870 {
871  const SwWriteTableRows& aRows = m_pTableWrt->GetRows();
872  SwWriteTableRow* pRow = aRows[pTableTextNodeInfoInner->getRow()].get();
873  const SwWriteTableCell* const pCell
874  = pRow->GetCells()[pTableTextNodeInfoInner->getCell()].get();
875  const SwFrameFormat* pCellFormat = pCell->GetBox()->GetFrameFormat();
876 
877  // Text direction.
878  if (SvxFrameDirection::Vertical_RL_TB == m_rExport.TrueFrameDirection(*pCellFormat))
879  m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CLTXTBRL);
880  else if (SvxFrameDirection::Vertical_LR_BT == m_rExport.TrueFrameDirection(*pCellFormat))
881  m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CLTXBTLR);
882 
883  const SfxPoolItem* pItem;
884 
885  // vertical merges
886  if (pCell->GetRowSpan() > 1)
887  m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CLVMGF);
888  else if (pCell->GetRowSpan() == 0)
889  m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CLVMRG);
890 
891  // vertical alignment
892  if (pCellFormat->GetAttrSet().HasItem(RES_VERT_ORIENT, &pItem))
893  switch (static_cast<const SwFormatVertOrient*>(pItem)->GetVertOrient())
894  {
895  case text::VertOrientation::CENTER:
896  m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CLVERTALC);
897  break;
898  case text::VertOrientation::BOTTOM:
899  m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CLVERTALB);
900  break;
901  default:
902  m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CLVERTALT);
903  break;
904  }
905 }
906 
908 {
909  // This is called when the nested table ends in a cell, and there's no
910  // paragraph behind that; so we must check for the ends of cell, rows,
911  // and tables
912  FinishTableRowCell(pNodeInfoInner);
913 }
914 
916  ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)
917 {
918  const SwTable* pTable = pTableTextNodeInfoInner->getTable();
919  SwFrameFormat* pFormat = pTable->GetFrameFormat();
920 
921  OStringBuffer aTableAdjust(OOO_STRING_SVTOOLS_RTF_TRQL);
922  switch (pFormat->GetHoriOrient().GetHoriOrient())
923  {
924  case text::HoriOrientation::CENTER:
925  aTableAdjust.setLength(0);
926  aTableAdjust.append(OOO_STRING_SVTOOLS_RTF_TRQC);
927  break;
928  case text::HoriOrientation::RIGHT:
929  aTableAdjust.setLength(0);
930  aTableAdjust.append(OOO_STRING_SVTOOLS_RTF_TRQR);
931  break;
933  case text::HoriOrientation::LEFT_AND_WIDTH:
934  aTableAdjust.append(OOO_STRING_SVTOOLS_RTF_TRLEFT);
935  aTableAdjust.append(static_cast<sal_Int32>(pFormat->GetLRSpace().GetLeft()));
936  break;
937  default:
938  break;
939  }
940 
941  m_aRowDefs.append(aTableAdjust.makeStringAndClear());
942 }
943 
945  ww8::WW8TableNodeInfoInner::Pointer_t /*pTableTextNodeInfoInner*/)
946 {
947  SAL_INFO("sw.rtf", "TODO: " << OSL_THIS_FUNC);
948 }
949 
950 void RtfAttributeOutput::TableRowEnd(sal_uInt32 /*nDepth*/) { /* noop, see EndTableRow() */}
951 
952 /*
953  * Our private table methods.
954  */
955 
957  const ww8::WW8TableNodeInfoInner::Pointer_t& pTableTextNodeInfoInner)
958 {
959  const SwTable* pTable = pTableTextNodeInfoInner->getTable();
960  if (m_pTableWrt && pTable == m_pTableWrt->GetTable())
961  return;
962 
963  long nPageSize = 0;
964  bool bRelBoxSize = false;
965 
966  // Create the SwWriteTable instance to use col spans
967  GetTablePageSize(pTableTextNodeInfoInner.get(), nPageSize, bRelBoxSize);
968 
969  const SwFrameFormat* pFormat = pTable->GetFrameFormat();
970  const sal_uInt32 nTableSz = pFormat->GetFrameSize().GetWidth();
971 
972  const SwHTMLTableLayout* pLayout = pTable->GetHTMLTableLayout();
973  if (pLayout && pLayout->IsExportable())
974  m_pTableWrt = std::make_unique<SwWriteTable>(pTable, pLayout);
975  else
976  m_pTableWrt = std::make_unique<SwWriteTable>(pTable, pTable->GetTabLines(), nPageSize,
977  nTableSz, false);
978 }
979 
981 {
982  // To trigger calling InitTableHelper()
983  m_pTableWrt.reset();
984 }
985 
987  const ww8::WW8TableNodeInfoInner::Pointer_t& pTableTextNodeInfoInner)
988 {
989  sal_uInt32 nCurrentDepth = pTableTextNodeInfoInner->getDepth();
990  SAL_INFO("sw.rtf", OSL_THIS_FUNC << ", (depth is " << nCurrentDepth << ")");
991  m_bTableRowEnded = false;
992 
993  TableDefinition(pTableTextNodeInfoInner);
994 
995  if (!m_bLastTable)
996  m_aTables.push_back(m_aRowDefs.makeStringAndClear());
997 
998  // We'll write the table definition for nested tables later
999  if (nCurrentDepth > 1)
1000  return;
1001  // Empty the previous row closing buffer before starting the new one,
1002  // necessary for subtables.
1003  m_rExport.Strm().WriteOString(m_aAfterRuns.makeStringAndClear());
1004  m_rExport.Strm().WriteOString(m_aRowDefs.makeStringAndClear());
1005 }
1006 
1007 void RtfAttributeOutput::StartTableCell() { m_bTableCellOpen = true; }
1008 
1010  const ww8::WW8TableNodeInfoInner::Pointer_t& pTableTextNodeInfoInner)
1011 {
1012  TableDefaultBorders(pTableTextNodeInfoInner);
1013  TableBackgrounds(pTableTextNodeInfoInner);
1014  TableVerticalCell(pTableTextNodeInfoInner);
1015 }
1016 
1018 {
1019  SAL_INFO("sw.rtf", OSL_THIS_FUNC << ", (depth is " << m_nTableDepth << ")");
1020 
1021  if (!m_bWroteCellInfo)
1022  {
1023  m_aAfterRuns.append(OOO_STRING_SVTOOLS_RTF_INTBL);
1024  m_aAfterRuns.append(OOO_STRING_SVTOOLS_RTF_ITAP);
1025  m_aAfterRuns.append(static_cast<sal_Int32>(m_nTableDepth));
1026  }
1027  if (m_nTableDepth > 1)
1028  m_aAfterRuns.append(OOO_STRING_SVTOOLS_RTF_NESTCELL);
1029  else
1030  m_aAfterRuns.append(OOO_STRING_SVTOOLS_RTF_CELL);
1031 
1032  m_bTableCellOpen = false;
1033  m_bTableAfterCell = true;
1034  m_bWroteCellInfo = false;
1035  if (m_aCells[m_nTableDepth] > 0)
1036  m_aCells[m_nTableDepth]--;
1037 }
1038 
1040 {
1041  SAL_INFO("sw.rtf", OSL_THIS_FUNC << ", (depth is " << m_nTableDepth << ")");
1042 
1043  // Trying to end the row without writing the required number of cells? Fill with empty ones.
1044  for (sal_uInt32 i = 0; i < m_aCells[m_nTableDepth]; i++)
1045  m_aAfterRuns.append(OOO_STRING_SVTOOLS_RTF_CELL);
1046 
1047  if (m_nTableDepth > 1)
1048  {
1049  m_aAfterRuns.append(
1051  if (!m_aRowDefs.isEmpty())
1052  m_aAfterRuns.append(m_aRowDefs.makeStringAndClear());
1053  else if (!m_aTables.empty())
1054  {
1055  m_aAfterRuns.append(m_aTables.back());
1056  m_aTables.pop_back();
1057  }
1058  m_aAfterRuns.append(OOO_STRING_SVTOOLS_RTF_NESTROW
1059  "}"
1061  }
1062  else
1063  {
1064  if (!m_aTables.empty())
1065  {
1066  m_aAfterRuns.append(m_aTables.back());
1067  m_aTables.pop_back();
1068  }
1069  m_aAfterRuns.append(OOO_STRING_SVTOOLS_RTF_ROW).append(OOO_STRING_SVTOOLS_RTF_PARD);
1070  }
1071  m_bTableRowEnded = true;
1072 }
1073 
1075 {
1076  if (m_nTableDepth > 0)
1077  {
1078  m_nTableDepth--;
1079  m_pTableWrt.reset();
1080  }
1081 
1082  // We closed the table; if it is a nested table, the cell that contains it
1083  // still continues
1084  m_bTableCellOpen = true;
1085 
1086  // Cleans the table helper
1087  m_pTableWrt.reset();
1088 }
1089 
1091 {
1092  if (pInner)
1093  {
1094  // Where are we in the table
1095  sal_uInt32 nRow = pInner->getRow();
1096 
1097  const SwTable* pTable = pInner->getTable();
1098  const SwTableLines& rLines = pTable->GetTabLines();
1099  sal_uInt16 nLinesCount = rLines.size();
1100 
1101  if (pInner->isEndOfCell())
1102  EndTableCell();
1103 
1104  // This is a line end
1105  if (pInner->isEndOfLine())
1106  EndTableRow();
1107 
1108  // This is the end of the table
1109  if (pInner->isEndOfLine() && (nRow + 1) == nLinesCount)
1110  EndTable();
1111  }
1112 }
1113 
1115 {
1116  m_rExport.Strm()
1117  .WriteCharPtr(SAL_NEWLINE_STRING)
1118  .WriteChar('{')
1119  .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_COLORTBL);
1120  m_rExport.OutColorTable();
1121  OSL_ENSURE(m_aStylesheet.getLength() == 0, "m_aStylesheet is not empty");
1122  m_aStylesheet.append(SAL_NEWLINE_STRING);
1123  m_aStylesheet.append('{');
1124  m_aStylesheet.append(OOO_STRING_SVTOOLS_RTF_STYLESHEET);
1125 }
1126 
1127 void RtfAttributeOutput::EndStyles(sal_uInt16 /*nNumberOfStyles*/)
1128 {
1129  m_rExport.Strm().WriteChar('}');
1130  m_rExport.Strm().WriteOString(m_aStylesheet.makeStringAndClear());
1131  m_rExport.Strm().WriteChar('}');
1132 }
1133 
1134 void RtfAttributeOutput::DefaultStyle() { /* noop, the default style is always 0 in RTF */}
1135 
1136 void RtfAttributeOutput::StartStyle(const OUString& rName, StyleType eType, sal_uInt16 nBase,
1137  sal_uInt16 nNext, sal_uInt16 /*nWwId*/, sal_uInt16 nId,
1138  bool bAutoUpdate)
1139 {
1140  SAL_INFO("sw.rtf", OSL_THIS_FUNC << ", rName = '" << rName << "'");
1141 
1142  m_aStylesheet.append('{');
1143  if (eType == STYLE_TYPE_PARA)
1144  m_aStylesheet.append(OOO_STRING_SVTOOLS_RTF_S);
1145  else
1147  m_aStylesheet.append(static_cast<sal_Int32>(nId));
1148 
1149  if (nBase != 0x0FFF)
1150  {
1151  m_aStylesheet.append(OOO_STRING_SVTOOLS_RTF_SBASEDON);
1152  m_aStylesheet.append(static_cast<sal_Int32>(nBase));
1153  }
1154 
1155  m_aStylesheet.append(OOO_STRING_SVTOOLS_RTF_SNEXT);
1156  m_aStylesheet.append(static_cast<sal_Int32>(nNext));
1157 
1158  if (bAutoUpdate)
1159  m_aStylesheet.append(OOO_STRING_SVTOOLS_RTF_SAUTOUPD);
1160 
1161  m_rStyleName = rName;
1162  m_nStyleId = nId;
1163 }
1164 
1166 {
1167  OString aStyles = MoveCharacterProperties();
1168  m_rExport.InsStyle(m_nStyleId, aStyles);
1169  m_aStylesheet.append(aStyles);
1170  m_aStylesheet.append(' ');
1171  m_aStylesheet.append(
1172  msfilter::rtfutil::OutString(m_rStyleName, m_rExport.GetCurrentEncoding()));
1173  m_aStylesheet.append(";}");
1174  m_aStylesheet.append(SAL_NEWLINE_STRING);
1175 }
1176 
1177 void RtfAttributeOutput::StartStyleProperties(bool /*bParProp*/, sal_uInt16 /*nStyle*/)
1178 {
1179  /* noop */
1180 }
1181 
1182 void RtfAttributeOutput::EndStyleProperties(bool /*bParProp*/) { /* noop */}
1183 
1185 {
1186  if (nLvl >= WW8ListManager::nMaxLevel)
1187  nLvl = WW8ListManager::nMaxLevel - 1;
1188 
1189  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ILVL);
1190  m_aStyles.append(static_cast<sal_Int32>(nLvl));
1191  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_OUTLINELEVEL);
1192  m_aStyles.append(static_cast<sal_Int32>(nLvl));
1193 }
1194 
1196 {
1197  if (bBreak)
1198  {
1199  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PAGEBB);
1200  }
1201 }
1202 
1203 void RtfAttributeOutput::SectionBreak(sal_uInt8 nC, bool /*bBreakAfter*/,
1204  const WW8_SepInfo* pSectionInfo)
1205 {
1206  switch (nC)
1207  {
1208  case msword::ColumnBreak:
1209  m_nColBreakNeeded = true;
1210  break;
1211  case msword::PageBreak:
1212  if (pSectionInfo)
1213  m_rExport.SectionProperties(*pSectionInfo);
1214  break;
1215  }
1216 }
1217 
1219 {
1220  if (m_bIsBeforeFirstParagraph)
1221  return;
1222 
1224  if (!m_bBufferSectionBreaks)
1225  m_rExport.Strm().WriteOString(m_aSectionBreaks.makeStringAndClear());
1226 }
1227 
1229 {
1230  /*
1231  * noop, \sect must go to StartSection or Word won't notice multiple
1232  * columns...
1233  */
1234 }
1235 
1237 {
1238  m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_SECTUNLOCKED);
1239  m_aSectionBreaks.append(static_cast<sal_Int32>(!bProtected));
1240 }
1241 
1243  const SwLineNumberInfo& rLnNumInfo)
1244 {
1245  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_LINEMOD);
1246  m_rExport.OutLong(rLnNumInfo.GetCountBy());
1247  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_LINEX);
1248  m_rExport.OutLong(rLnNumInfo.GetPosFromLeft());
1249  if (!rLnNumInfo.IsRestartEachPage())
1250  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_LINECONT);
1251 
1252  if (nRestartNo > 0)
1253  {
1254  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_LINESTARTS);
1255  m_rExport.OutLong(nRestartNo);
1256  }
1257 }
1258 
1260 {
1261  /*
1262  * noop, handled in RtfExport::WriteHeaderFooter()
1263  */
1264 }
1265 
1267  const SwFrameFormat* /*pFirstPageFormat*/)
1268 {
1269  const SvxBoxItem& rBox = pFormat->GetBox();
1270  const editeng::SvxBorderLine* pLine = rBox.GetTop();
1271  if (pLine)
1272  m_aSectionBreaks.append(OutBorderLine(m_rExport, pLine, OOO_STRING_SVTOOLS_RTF_PGBRDRT,
1273  rBox.GetDistance(SvxBoxItemLine::TOP)));
1274  pLine = rBox.GetBottom();
1275  if (pLine)
1276  m_aSectionBreaks.append(OutBorderLine(m_rExport, pLine, OOO_STRING_SVTOOLS_RTF_PGBRDRB,
1277  rBox.GetDistance(SvxBoxItemLine::BOTTOM)));
1278  pLine = rBox.GetLeft();
1279  if (pLine)
1280  m_aSectionBreaks.append(OutBorderLine(m_rExport, pLine, OOO_STRING_SVTOOLS_RTF_PGBRDRL,
1281  rBox.GetDistance(SvxBoxItemLine::LEFT)));
1282  pLine = rBox.GetRight();
1283  if (pLine)
1284  m_aSectionBreaks.append(OutBorderLine(m_rExport, pLine, OOO_STRING_SVTOOLS_RTF_PGBRDRR,
1285  rBox.GetDistance(SvxBoxItemLine::RIGHT)));
1286 }
1287 
1289 {
1290  m_rExport.Strm().WriteCharPtr(bBiDi ? OOO_STRING_SVTOOLS_RTF_RTLSECT
1292 }
1293 
1295  const ::std::optional<sal_uInt16>& oPageRestartNumber)
1296 {
1297  if (oPageRestartNumber)
1298  {
1299  m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_PGNSTARTS);
1300  m_aSectionBreaks.append(static_cast<sal_Int32>(*oPageRestartNumber));
1301  m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_PGNRESTART);
1302  }
1303 
1304  const char* pStr = nullptr;
1305  switch (nNumType)
1306  {
1310  break;
1314  break;
1315  case SVX_NUM_ROMAN_UPPER:
1317  break;
1318  case SVX_NUM_ROMAN_LOWER:
1320  break;
1321 
1322  case SVX_NUM_ARABIC:
1324  break;
1325  }
1326  if (pStr)
1327  m_aSectionBreaks.append(pStr);
1328 }
1329 
1331 {
1332  SAL_INFO("sw.rtf", OSL_THIS_FUNC << ", nBreakCode = " << int(nBreakCode));
1333 
1334  /*
1335  * break code: 0 No break, 1 New column
1336  * 2 New page, 3 Even page, 4 Odd page
1337  */
1338  const char* sType = nullptr;
1339  switch (nBreakCode)
1340  {
1341  case 1:
1343  break;
1344  case 2:
1346  break;
1347  case 3:
1349  break;
1350  case 4:
1352  break;
1353  default:
1355  break;
1356  }
1357  m_aSectionBreaks.append(sType);
1358  if (!m_bBufferSectionBreaks)
1359  m_rExport.Strm().WriteOString(m_aSectionBreaks.makeStringAndClear());
1360 }
1361 
1363 {
1364  WriteFootnoteEndnotePr(true, m_rExport.m_pDoc->GetFootnoteInfo());
1365  WriteFootnoteEndnotePr(false, m_rExport.m_pDoc->GetEndNoteInfo());
1366 }
1367 
1369 {
1370  const char* pOut = nullptr;
1371 
1372  if (bFootnote)
1373  {
1374  switch (rInfo.m_aFormat.GetNumberingType())
1375  {
1376  default:
1378  break;
1382  break;
1386  break;
1387  case SVX_NUM_ROMAN_LOWER:
1389  break;
1390  case SVX_NUM_ROMAN_UPPER:
1392  break;
1395  break;
1396  }
1397  }
1398  else
1399  {
1400  switch (rInfo.m_aFormat.GetNumberingType())
1401  {
1402  default:
1404  break;
1408  break;
1412  break;
1413  case SVX_NUM_ROMAN_LOWER:
1415  break;
1416  case SVX_NUM_ROMAN_UPPER:
1418  break;
1421  break;
1422  }
1423  }
1424 
1425  m_aSectionBreaks.append(pOut);
1426 
1427  if (!m_bBufferSectionBreaks)
1428  {
1429  m_rExport.Strm().WriteOString(m_aSectionBreaks.makeStringAndClear());
1430  }
1431 }
1432 
1433 void RtfAttributeOutput::NumberingDefinition(sal_uInt16 nId, const SwNumRule& /*rRule*/)
1434 {
1435  m_rExport.Strm().WriteChar('{').WriteCharPtr(OOO_STRING_SVTOOLS_RTF_LISTOVERRIDE);
1436  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_LISTID);
1437  m_rExport.OutULong(nId);
1438  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_LISTOVERRIDECOUNT).WriteChar('0');
1439  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_LS);
1440  m_rExport.OutULong(nId).WriteChar('}');
1441 }
1442 
1444 {
1445  m_rExport.Strm()
1446  .WriteChar('{')
1447  .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_LIST)
1449  m_rExport.OutULong(nId);
1450  m_nListId = nId;
1451 }
1452 
1454 {
1455  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_LISTID);
1456  m_rExport.OutULong(m_nListId).WriteChar('}').WriteCharPtr(SAL_NEWLINE_STRING);
1457 }
1458 
1459 void RtfAttributeOutput::NumberingLevel(sal_uInt8 nLevel, sal_uInt16 nStart,
1460  sal_uInt16 nNumberingType, SvxAdjust eAdjust,
1461  const sal_uInt8* pNumLvlPos, sal_uInt8 nFollow,
1462  const wwFont* pFont, const SfxItemSet* pOutSet,
1463  sal_Int16 nIndentAt, sal_Int16 nFirstLineIndex,
1464  sal_Int16 /*nListTabPos*/, const OUString& rNumberingString,
1465  const SvxBrushItem* pBrush)
1466 {
1467  m_rExport.Strm().WriteCharPtr(SAL_NEWLINE_STRING);
1468  if (nLevel > 8) // RTF knows only 9 levels
1469  m_rExport.Strm()
1470  .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_IGNORE)
1471  .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_SOUTLVL);
1472 
1473  m_rExport.Strm().WriteChar('{').WriteCharPtr(OOO_STRING_SVTOOLS_RTF_LISTLEVEL);
1474 
1475  sal_uInt16 nVal = 0;
1476  switch (nNumberingType)
1477  {
1478  case SVX_NUM_ROMAN_UPPER:
1479  nVal = 1;
1480  break;
1481  case SVX_NUM_ROMAN_LOWER:
1482  nVal = 2;
1483  break;
1486  nVal = 3;
1487  break;
1490  nVal = 4;
1491  break;
1493  nVal = 14;
1494  break;
1495  case SVX_NUM_CIRCLE_NUMBER:
1496  nVal = 18;
1497  break;
1499  nVal = 35;
1500  if (pOutSet)
1501  {
1502  const SvxLanguageItem& rLang = pOutSet->Get(RES_CHRATR_CJK_LANGUAGE);
1504  {
1505  nVal = 39;
1506  }
1507  }
1508  break;
1510  nVal = 38;
1511  break;
1513  nVal = 34;
1514  break;
1515  case SVX_NUM_TIAN_GAN_ZH:
1516  nVal = 30;
1517  break;
1518  case SVX_NUM_DI_ZI_ZH:
1519  nVal = 31;
1520  break;
1522  nVal = 16;
1523  break;
1525  nVal = 20;
1526  break;
1528  nVal = 12;
1529  break;
1531  nVal = 21;
1532  break;
1534  nVal = 13;
1535  break;
1536  case style::NumberingType::HANGUL_SYLLABLE_KO:
1537  nVal = 24;
1538  break; // ganada
1539  case style::NumberingType::HANGUL_JAMO_KO:
1540  nVal = 25;
1541  break; // chosung
1542  case style::NumberingType::HANGUL_CIRCLED_SYLLABLE_KO:
1543  nVal = 24;
1544  break;
1545  case style::NumberingType::HANGUL_CIRCLED_JAMO_KO:
1546  nVal = 25;
1547  break;
1548  case style::NumberingType::NUMBER_HANGUL_KO:
1549  nVal = 41;
1550  break;
1551  case style::NumberingType::NUMBER_UPPER_KO:
1552  nVal = 44;
1553  break;
1554 
1555  case SVX_NUM_BITMAP:
1556  case SVX_NUM_CHAR_SPECIAL:
1557  nVal = 23;
1558  break;
1559  case SVX_NUM_NUMBER_NONE:
1560  nVal = 255;
1561  break;
1562  case SVX_NUM_ARABIC_ZERO:
1563  nVal = 22;
1564  break;
1565  }
1566  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_LEVELNFC);
1567  m_rExport.OutULong(nVal);
1568 
1569  switch (eAdjust)
1570  {
1571  case SvxAdjust::Center:
1572  nVal = 1;
1573  break;
1574  case SvxAdjust::Right:
1575  nVal = 2;
1576  break;
1577  default:
1578  nVal = 0;
1579  break;
1580  }
1581  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_LEVELJC);
1582  m_rExport.OutULong(nVal);
1583 
1584  // bullet
1585  if (nNumberingType == SVX_NUM_BITMAP && pBrush)
1586  {
1587  int nIndex = m_rExport.GetGrfIndex(*pBrush);
1588  if (nIndex != -1)
1589  {
1590  m_rExport.Strm().WriteCharPtr(LO_STRING_SVTOOLS_RTF_LEVELPICTURE);
1591  m_rExport.OutULong(nIndex);
1592  }
1593  }
1594 
1595  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_LEVELSTARTAT);
1596  m_rExport.OutULong(nStart);
1597 
1598  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_LEVELFOLLOW);
1599  m_rExport.OutULong(nFollow);
1600 
1601  // leveltext group
1602  m_rExport.Strm().WriteChar('{').WriteCharPtr(OOO_STRING_SVTOOLS_RTF_LEVELTEXT).WriteChar(' ');
1603 
1604  if (SVX_NUM_CHAR_SPECIAL == nNumberingType || SVX_NUM_BITMAP == nNumberingType)
1605  {
1606  m_rExport.Strm().WriteCharPtr("\\'01");
1607  sal_Unicode cChar = rNumberingString[0];
1608  m_rExport.Strm().WriteCharPtr("\\u");
1609  m_rExport.OutULong(cChar);
1610  m_rExport.Strm().WriteCharPtr(" ?");
1611  }
1612  else
1613  {
1614  m_rExport.Strm().WriteCharPtr("\\'").WriteCharPtr(
1615  msfilter::rtfutil::OutHex(rNumberingString.getLength(), 2).getStr());
1616  m_rExport.Strm().WriteCharPtr(msfilter::rtfutil::OutString(rNumberingString,
1617  m_rExport.GetDefaultEncoding(),
1618  /*bUnicode =*/false)
1619  .getStr());
1620  }
1621 
1622  m_rExport.Strm().WriteCharPtr(";}");
1623 
1624  // write the levelnumbers
1625  m_rExport.Strm().WriteCharPtr("{").WriteCharPtr(OOO_STRING_SVTOOLS_RTF_LEVELNUMBERS);
1626  for (sal_uInt8 i = 0; i <= nLevel && pNumLvlPos[i]; ++i)
1627  {
1628  m_rExport.Strm().WriteCharPtr("\\'").WriteCharPtr(
1629  msfilter::rtfutil::OutHex(pNumLvlPos[i], 2).getStr());
1630  }
1631  m_rExport.Strm().WriteCharPtr(";}");
1632 
1633  if (pOutSet)
1634  {
1635  if (pFont)
1636  {
1637  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_F);
1638  m_rExport.OutULong(m_rExport.m_aFontHelper.GetId(*pFont));
1639  }
1640  m_rExport.OutputItemSet(*pOutSet, false, true, i18n::ScriptType::LATIN,
1641  m_rExport.m_bExportModeRTF);
1642  const OString aProperties = MoveCharacterProperties(true);
1643  m_rExport.Strm().WriteOString(aProperties);
1644  }
1645 
1646  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_FI);
1647  m_rExport.OutLong(nFirstLineIndex).WriteCharPtr(OOO_STRING_SVTOOLS_RTF_LI);
1648  m_rExport.OutLong(nIndentAt);
1649 
1650  m_rExport.Strm().WriteChar('}');
1651  if (nLevel > 8)
1652  m_rExport.Strm().WriteChar('}');
1653 }
1654 
1655 void RtfAttributeOutput::WriteField_Impl(const SwField* const pField, ww::eField /*eType*/,
1656  const OUString& rFieldCmd, FieldFlags nMode)
1657 {
1658  // If there are no field instructions, don't export it as a field.
1659  bool bHasInstructions = !rFieldCmd.isEmpty();
1660  if (FieldFlags::All == nMode)
1661  {
1662  if (bHasInstructions)
1663  {
1664  m_aRunText->append("{" OOO_STRING_SVTOOLS_RTF_FIELD);
1666  " ");
1667  m_aRunText->append(
1668  msfilter::rtfutil::OutString(rFieldCmd, m_rExport.GetCurrentEncoding()));
1669  m_aRunText->append("}{" OOO_STRING_SVTOOLS_RTF_FLDRSLT " ");
1670  }
1671  if (pField)
1672  m_aRunText->append(msfilter::rtfutil::OutString(pField->ExpandField(true, nullptr),
1673  m_rExport.GetDefaultEncoding()));
1674  if (bHasInstructions)
1675  m_aRunText->append("}}");
1676  }
1677  else
1678  {
1679  if (nMode & FieldFlags::CmdStart)
1680  {
1681  m_aRunText->append("{" OOO_STRING_SVTOOLS_RTF_FIELD);
1683  // paragraph break closes group so open another one "inside" to
1684  " {"); // prevent leaving the field instruction
1685  }
1686  if (bHasInstructions)
1687  m_aRunText->append(
1688  msfilter::rtfutil::OutString(rFieldCmd, m_rExport.GetCurrentEncoding()));
1689  if (nMode & FieldFlags::CmdEnd)
1690  {
1691  m_aRunText->append("}}{" OOO_STRING_SVTOOLS_RTF_FLDRSLT " {");
1692  }
1693  if (nMode & FieldFlags::Close)
1694  {
1695  m_aRunText->append("}}}");
1696  }
1697  }
1698 }
1699 
1700 void RtfAttributeOutput::WriteBookmarks_Impl(std::vector<OUString>& rStarts,
1701  std::vector<OUString>& rEnds)
1702 {
1703  for (const auto& rStart : rStarts)
1704  {
1706  m_aRun->append(msfilter::rtfutil::OutString(rStart, m_rExport.GetCurrentEncoding()));
1707  m_aRun->append('}');
1708  }
1709  rStarts.clear();
1710 
1711  for (const auto& rEnd : rEnds)
1712  {
1714  m_aRun->append(msfilter::rtfutil::OutString(rEnd, m_rExport.GetCurrentEncoding()));
1715  m_aRun->append('}');
1716  }
1717  rEnds.clear();
1718 }
1719 
1720 void RtfAttributeOutput::WriteAnnotationMarks_Impl(std::vector<OUString>& rStarts,
1721  std::vector<OUString>& rEnds)
1722 {
1723  for (const auto& rStart : rStarts)
1724  {
1725  OString rName = OUStringToOString(rStart, RTL_TEXTENCODING_UTF8);
1726 
1727  // Output the annotation mark
1728  const sal_Int32 nId = m_nNextAnnotationMarkId++;
1729  m_rOpenedAnnotationMarksIds[rName] = nId;
1731  m_aRun->append(OString::number(nId).getStr());
1732  m_aRun->append('}');
1733  }
1734  rStarts.clear();
1735 
1736  for (const auto& rEnd : rEnds)
1737  {
1738  OString rName = OUStringToOString(rEnd, RTL_TEXTENCODING_UTF8);
1739 
1740  // Get the id of the annotation mark
1741  auto it = m_rOpenedAnnotationMarksIds.find(rName);
1742  if (it != m_rOpenedAnnotationMarksIds.end())
1743  {
1744  const sal_Int32 nId = it->second;
1746  m_aRun->append(OString::number(nId).getStr());
1747  m_aRun->append('}');
1748  m_rOpenedAnnotationMarksIds.erase(rName);
1749 
1750  if (m_aPostitFields.find(nId) != m_aPostitFields.end())
1751  {
1752  m_aRunText->append("{");
1753  m_nCurrentAnnotationMarkId = nId;
1754  PostitField(m_aPostitFields[nId]);
1755  m_nCurrentAnnotationMarkId = -1;
1756  m_aRunText->append("}");
1757  }
1758  }
1759  }
1760  rEnds.clear();
1761 }
1762 
1764  const char* pStr, bool bTitlepg)
1765 {
1766  OStringBuffer aSectionBreaks = m_aSectionBreaks;
1767  m_aSectionBreaks.setLength(0);
1768  RtfStringBuffer aRun = m_aRun;
1769  m_aRun.clear();
1770 
1771  m_aSectionHeaders.append(bHeader ? OOO_STRING_SVTOOLS_RTF_HEADERY
1773  m_aSectionHeaders.append(
1774  static_cast<sal_Int32>(m_rExport.m_pCurrentPageDesc->GetMaster().GetULSpace().GetUpper()));
1775  if (bTitlepg)
1776  m_aSectionHeaders.append(OOO_STRING_SVTOOLS_RTF_TITLEPG);
1777  m_aSectionHeaders.append('{');
1778  m_aSectionHeaders.append(pStr);
1779  m_bBufferSectionHeaders = true;
1780  m_rExport.WriteHeaderFooterText(rFormat, bHeader);
1781  m_bBufferSectionHeaders = false;
1782  m_aSectionHeaders.append('}');
1783 
1784  m_aSectionBreaks = aSectionBreaks;
1785  m_aRun = aRun;
1786 }
1787 
1788 namespace
1789 {
1790 void lcl_TextFrameShadow(std::vector<std::pair<OString, OString>>& rFlyProperties,
1791  const SwFrameFormat& rFrameFormat)
1792 {
1793  const SvxShadowItem& aShadowItem = rFrameFormat.GetShadow();
1794  if (aShadowItem.GetLocation() == SvxShadowLocation::NONE)
1795  return;
1796 
1797  rFlyProperties.push_back(std::make_pair<OString, OString>("fShadow", OString::number(1)));
1798 
1799  const Color& rColor = aShadowItem.GetColor();
1800  // We in fact need RGB to BGR, but the transformation is symmetric.
1801  rFlyProperties.push_back(std::make_pair<OString, OString>(
1802  "shadowColor", OString::number(wwUtility::RGBToBGR(rColor))));
1803 
1804  // Twips -> points -> EMUs -- hacky, the intermediate step hides rounding errors on roundtrip.
1805  OString aShadowWidth = OString::number(sal_Int32(aShadowItem.GetWidth() / 20) * 12700);
1806  OString aOffsetX;
1807  OString aOffsetY;
1808  switch (aShadowItem.GetLocation())
1809  {
1810  case SvxShadowLocation::TopLeft:
1811  aOffsetX = "-" + aShadowWidth;
1812  aOffsetY = "-" + aShadowWidth;
1813  break;
1814  case SvxShadowLocation::TopRight:
1815  aOffsetX = aShadowWidth;
1816  aOffsetY = "-" + aShadowWidth;
1817  break;
1818  case SvxShadowLocation::BottomLeft:
1819  aOffsetX = "-" + aShadowWidth;
1820  aOffsetY = aShadowWidth;
1821  break;
1822  case SvxShadowLocation::BottomRight:
1823  aOffsetX = aShadowWidth;
1824  aOffsetY = aShadowWidth;
1825  break;
1826  case SvxShadowLocation::NONE:
1827  case SvxShadowLocation::End:
1828  break;
1829  }
1830  if (!aOffsetX.isEmpty())
1831  rFlyProperties.emplace_back("shadowOffsetX", aOffsetX);
1832  if (!aOffsetY.isEmpty())
1833  rFlyProperties.emplace_back("shadowOffsetY", aOffsetY);
1834 }
1835 
1836 void lcl_TextFrameRelativeSize(std::vector<std::pair<OString, OString>>& rFlyProperties,
1837  const SwFrameFormat& rFrameFormat)
1838 {
1839  const SwFormatFrameSize& rSize = rFrameFormat.GetFrameSize();
1840 
1841  // Relative size of the Text Frame.
1842  const sal_uInt8 nWidthPercent = rSize.GetWidthPercent();
1843  if (nWidthPercent && nWidthPercent != SwFormatFrameSize::SYNCED)
1844  {
1845  rFlyProperties.push_back(
1846  std::make_pair<OString, OString>("pctHoriz", OString::number(nWidthPercent * 10)));
1847 
1848  OString aRelation;
1849  switch (rSize.GetWidthPercentRelation())
1850  {
1851  case text::RelOrientation::PAGE_FRAME:
1852  aRelation = "1"; // page
1853  break;
1854  default:
1855  aRelation = "0"; // margin
1856  break;
1857  }
1858  rFlyProperties.emplace_back(std::make_pair("sizerelh", aRelation));
1859  }
1860  const sal_uInt8 nHeightPercent = rSize.GetHeightPercent();
1861  if (nHeightPercent && nHeightPercent != SwFormatFrameSize::SYNCED)
1862  {
1863  rFlyProperties.push_back(
1864  std::make_pair<OString, OString>("pctVert", OString::number(nHeightPercent * 10)));
1865 
1866  OString aRelation;
1867  switch (rSize.GetHeightPercentRelation())
1868  {
1869  case text::RelOrientation::PAGE_FRAME:
1870  aRelation = "1"; // page
1871  break;
1872  default:
1873  aRelation = "0"; // margin
1874  break;
1875  }
1876  rFlyProperties.emplace_back(std::make_pair("sizerelv", aRelation));
1877  }
1878 }
1879 }
1880 
1881 void RtfAttributeOutput::writeTextFrame(const ww8::Frame& rFrame, bool bTextBox)
1882 {
1883  RtfStringBuffer aRunText;
1884  if (bTextBox)
1885  {
1886  m_rExport.setStream();
1887  aRunText = m_aRunText;
1888  m_aRunText.clear();
1889  }
1890 
1891  m_rExport.Strm().WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_SHPTXT);
1892 
1893  {
1894  // Save table state, in case the inner text also contains a table.
1895  ww8::WW8TableInfo::Pointer_t pTableInfoOrig = m_rExport.m_pTableInfo;
1896  m_rExport.m_pTableInfo = std::make_shared<ww8::WW8TableInfo>();
1897  std::unique_ptr<SwWriteTable> pTableWrt(std::move(m_pTableWrt));
1898  sal_uInt32 nTableDepth = m_nTableDepth;
1899 
1900  m_nTableDepth = 0;
1901  /*
1902  * Save m_aRun as we should not lose the opening brace.
1903  * OTOH, just drop the contents of m_aRunText in case something
1904  * would be there, causing a problem later.
1905  */
1906  OString aSave = m_aRun.makeStringAndClear();
1907  // Also back m_bInRun and m_bSingleEmptyRun up.
1908  bool bInRunOrig = m_bInRun;
1909  m_bInRun = false;
1910  bool bSingleEmptyRunOrig = m_bSingleEmptyRun;
1911  m_bSingleEmptyRun = false;
1912  m_rExport.SetRTFFlySyntax(true);
1913 
1914  const SwFrameFormat& rFrameFormat = rFrame.GetFrameFormat();
1915  const SwNodeIndex* pNodeIndex = rFrameFormat.GetContent().GetContentIdx();
1916  sal_uLong nStt = pNodeIndex ? pNodeIndex->GetIndex() + 1 : 0;
1917  sal_uLong nEnd = pNodeIndex ? pNodeIndex->GetNode().EndOfSectionIndex() : 0;
1918  m_rExport.SaveData(nStt, nEnd);
1919  m_rExport.m_pParentFrame = &rFrame;
1920  m_rExport.WriteText();
1921  m_rExport.RestoreData();
1922 
1923  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PARD);
1924  m_rExport.SetRTFFlySyntax(false);
1925  m_aRun->append(aSave);
1926  m_aRunText.clear();
1927  m_bInRun = bInRunOrig;
1928  m_bSingleEmptyRun = bSingleEmptyRunOrig;
1929 
1930  // Restore table state.
1931  m_rExport.m_pTableInfo = pTableInfoOrig;
1932  m_pTableWrt = std::move(pTableWrt);
1933  m_nTableDepth = nTableDepth;
1934  }
1935 
1936  m_rExport.m_pParentFrame = nullptr;
1937 
1938  m_rExport.Strm().WriteChar('}'); // shptxt
1939 
1940  if (bTextBox)
1941  {
1942  m_aRunText = aRunText;
1943  m_aRunText->append(m_rExport.getStream());
1944  m_rExport.resetStream();
1945  }
1946 }
1947 
1953 {
1954 private:
1958  bool const m_bSingleEmptyRun;
1959  bool const m_bInRun;
1960 
1961 public:
1963  : m_rRtf(rRtf)
1964  , m_Run(std::move(rRtf.m_aRun))
1965  , m_RunText(std::move(rRtf.m_aRunText))
1966  , m_bSingleEmptyRun(rRtf.m_bSingleEmptyRun)
1967  , m_bInRun(rRtf.m_bInRun)
1968  {
1969  m_rRtf.m_rExport.setStream();
1970  }
1972  {
1973  m_rRtf.m_aRun = std::move(m_Run);
1974  m_rRtf.m_aRunText = std::move(m_RunText);
1975  m_rRtf.m_bSingleEmptyRun = m_bSingleEmptyRun;
1976  m_rRtf.m_bInRun = m_bInRun;
1977 
1978  m_rRtf.m_aRunText->append(m_rRtf.m_rExport.getStream());
1979  m_rRtf.m_rExport.resetStream();
1980  }
1981 };
1982 
1983 void RtfAttributeOutput::OutputFlyFrame_Impl(const ww8::Frame& rFrame, const Point& /*rNdTopLeft*/)
1984 {
1985  const SwNode* pNode = rFrame.GetContent();
1986  const SwGrfNode* pGrfNode = pNode ? pNode->GetGrfNode() : nullptr;
1987 
1988  switch (rFrame.GetWriterType())
1989  {
1990  case ww8::Frame::eTextBox:
1991  {
1992  // If this is a TextBox of a shape, then ignore: it's handled in RtfSdrExport::StartShape().
1994  break;
1995 
1996  SaveRunState const saved(*this);
1997 
1998  m_rExport.m_pParentFrame = &rFrame;
1999 
2000  m_rExport.Strm().WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_SHP);
2001  m_rExport.Strm().WriteCharPtr(
2003 
2004  // Shape properties.
2005  m_aFlyProperties.push_back(std::make_pair<OString, OString>(
2006  "shapeType", OString::number(ESCHER_ShpInst_TextBox)));
2007 
2008  // When a frame has some low height, but automatically expanded due
2009  // to lots of contents, this size contains the real size.
2010  const Size aSize = rFrame.GetSize();
2011  m_pFlyFrameSize = &aSize;
2012 
2013  m_rExport.m_bOutFlyFrameAttrs = true;
2014  m_rExport.SetRTFFlySyntax(true);
2015  m_rExport.OutputFormat(rFrame.GetFrameFormat(), false, false, true);
2016 
2017  // Write ZOrder.
2018  if (const SdrObject* pObject = rFrame.GetFrameFormat().FindRealSdrObject())
2019  {
2020  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_SHPZ);
2021  m_rExport.OutULong(pObject->GetOrdNum());
2022  }
2023 
2024  m_rExport.Strm().WriteOString(m_aRunText.makeStringAndClear());
2025  m_rExport.Strm().WriteOString(m_aStyles.makeStringAndClear());
2026  m_rExport.m_bOutFlyFrameAttrs = false;
2027  m_rExport.SetRTFFlySyntax(false);
2028  m_pFlyFrameSize = nullptr;
2029 
2030  const SwFrameFormat& rFrameFormat = rFrame.GetFrameFormat();
2031  lcl_TextFrameShadow(m_aFlyProperties, rFrameFormat);
2032  lcl_TextFrameRelativeSize(m_aFlyProperties, rFrameFormat);
2033 
2034  for (const std::pair<OString, OString>& rPair : m_aFlyProperties)
2035  {
2036  m_rExport.Strm().WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_SP "{");
2037  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_SN " ");
2038  m_rExport.Strm().WriteOString(rPair.first);
2039  m_rExport.Strm().WriteCharPtr("}{" OOO_STRING_SVTOOLS_RTF_SV " ");
2040  m_rExport.Strm().WriteOString(rPair.second);
2041  m_rExport.Strm().WriteCharPtr("}}");
2042  }
2043  m_aFlyProperties.clear();
2044 
2045  writeTextFrame(rFrame);
2046 
2047  m_rExport.Strm().WriteChar('}'); // shpinst
2048  m_rExport.Strm().WriteChar('}'); // shp
2049 
2050  m_rExport.Strm().WriteCharPtr(SAL_NEWLINE_STRING);
2051  }
2052  break;
2053  case ww8::Frame::eGraphic:
2054  if (pGrfNode)
2055  {
2056  m_aRunText.append(dynamic_cast<const SwFlyFrameFormat*>(&rFrame.GetFrameFormat()),
2057  pGrfNode);
2058  }
2059  else if (!rFrame.IsInline())
2060  {
2061  m_rExport.m_pParentFrame = &rFrame;
2062  m_rExport.SetRTFFlySyntax(true);
2063  m_rExport.OutputFormat(rFrame.GetFrameFormat(), false, false, true);
2064  m_rExport.SetRTFFlySyntax(false);
2065  m_aRunText->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE);
2066  m_rExport.OutputFormat(rFrame.GetFrameFormat(), false, false, true);
2067  m_aRunText->append('}');
2068  m_rExport.m_pParentFrame = nullptr;
2069  }
2070  break;
2071  case ww8::Frame::eDrawing:
2072  {
2073  const SdrObject* pSdrObj = rFrame.GetFrameFormat().FindRealSdrObject();
2074  if (pSdrObj)
2075  {
2076  m_aRunText->append("{" OOO_STRING_SVTOOLS_RTF_FIELD "{");
2077  m_aRunText->append(OOO_STRING_SVTOOLS_RTF_IGNORE);
2078  m_aRunText->append(OOO_STRING_SVTOOLS_RTF_FLDINST);
2079  m_aRunText->append(" SHAPE ");
2080  m_aRunText->append("}"
2082 
2083  m_rExport.SdrExporter().AddSdrObject(*pSdrObj);
2084 
2085  m_aRunText->append('}');
2086  m_aRunText->append('}');
2087  }
2088  }
2089  break;
2091  {
2092  const SwFrameFormat& rFrameFormat = rFrame.GetFrameFormat();
2093  const SdrObject* pObject = rFrameFormat.FindRealSdrObject();
2094 
2095  m_aRun->append("{" OOO_STRING_SVTOOLS_RTF_FIELD);
2097 
2098  if (pObject && pObject->GetObjInventor() == SdrInventor::FmForm)
2099  {
2100  if (auto pFormObj = dynamic_cast<const SdrUnoObj*>(pObject))
2101  {
2102  const uno::Reference<awt::XControlModel>& xControlModel
2103  = pFormObj->GetUnoControlModel();
2104  uno::Reference<lang::XServiceInfo> xInfo(xControlModel, uno::UNO_QUERY);
2105  if (xInfo.is())
2106  {
2107  uno::Reference<beans::XPropertySet> xPropSet(xControlModel, uno::UNO_QUERY);
2108  uno::Reference<beans::XPropertySetInfo> xPropSetInfo
2109  = xPropSet->getPropertySetInfo();
2110  OUString sName;
2111  if (xInfo->supportsService("com.sun.star.form.component.CheckBox"))
2112  {
2114  m_rExport.GetCurrentEncoding()));
2115  m_aRun->append(
2117  "{");
2118  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFTYPE "1"); // 1 = checkbox
2119  // checkbox size in half points, this seems to be always 20
2120  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFHPS "20");
2121 
2122  OUString aStr;
2123  sName = "Name";
2124  if (xPropSetInfo->hasPropertyByName(sName))
2125  {
2126  xPropSet->getPropertyValue(sName) >>= aStr;
2127  m_aRun->append(
2129  " ");
2130  m_aRun->append(
2131  OUStringToOString(aStr, m_rExport.GetCurrentEncoding()));
2132  m_aRun->append('}');
2133  }
2134 
2135  sName = "HelpText";
2136  if (xPropSetInfo->hasPropertyByName(sName))
2137  {
2138  xPropSet->getPropertyValue(sName) >>= aStr;
2139  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFOWNHELP);
2140  m_aRun->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE
2142  m_aRun->append(
2143  OUStringToOString(aStr, m_rExport.GetCurrentEncoding()));
2144  m_aRun->append('}');
2145  }
2146 
2147  sName = "HelpF1Text";
2148  if (xPropSetInfo->hasPropertyByName(sName))
2149  {
2150  xPropSet->getPropertyValue(sName) >>= aStr;
2151  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFOWNSTAT);
2152  m_aRun->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE
2154  m_aRun->append(
2155  OUStringToOString(aStr, m_rExport.GetCurrentEncoding()));
2156  m_aRun->append('}');
2157  }
2158 
2159  sal_Int16 nTemp = 0;
2160  xPropSet->getPropertyValue("DefaultState") >>= nTemp;
2161  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFDEFRES);
2162  m_aRun->append(static_cast<sal_Int32>(nTemp));
2163  xPropSet->getPropertyValue("State") >>= nTemp;
2164  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFRES);
2165  m_aRun->append(static_cast<sal_Int32>(nTemp));
2166 
2167  m_aRun->append("}}");
2168 
2169  // field result is empty, ffres already contains the form result
2170  m_aRun->append("}{" OOO_STRING_SVTOOLS_RTF_FLDRSLT " ");
2171  }
2172  else if (xInfo->supportsService("com.sun.star.form.component.TextField"))
2173  {
2174  OStringBuffer aBuf;
2175  OString aStr;
2176  OUString aTmp;
2177  const char* pStr;
2178 
2180  m_rExport.GetCurrentEncoding()));
2181  m_aRun->append(
2183  " ");
2184  for (int i = 0; i < 8; i++)
2185  aBuf.append(char(0x00));
2186  xPropSet->getPropertyValue("Name") >>= aTmp;
2187  aStr = OUStringToOString(aTmp, m_rExport.GetCurrentEncoding());
2188  aBuf.append(static_cast<char>(aStr.getLength()));
2189  aBuf.append(aStr);
2190  aBuf.append(char(0x00));
2191  xPropSet->getPropertyValue("DefaultText") >>= aTmp;
2192  aStr = OUStringToOString(aTmp, m_rExport.GetCurrentEncoding());
2193  aBuf.append(static_cast<char>(aStr.getLength()));
2194  aBuf.append(aStr);
2195  for (int i = 0; i < 11; i++)
2196  aBuf.append(char(0x00));
2197  aStr = aBuf.makeStringAndClear();
2198  pStr = aStr.getStr();
2199  for (int i = 0; i < aStr.getLength(); i++, pStr++)
2200  m_aRun->append(msfilter::rtfutil::OutHex(*pStr, 2));
2201  m_aRun->append('}');
2202  m_aRun->append("}{" OOO_STRING_SVTOOLS_RTF_FLDRSLT " ");
2203  xPropSet->getPropertyValue("Text") >>= aTmp;
2204  m_aRun->append(OUStringToOString(aTmp, m_rExport.GetCurrentEncoding()));
2205  m_aRun->append('}');
2206  m_aRun->append(
2208  "{");
2209  sName = "HelpText";
2210  if (xPropSetInfo->hasPropertyByName(sName))
2211  {
2212  xPropSet->getPropertyValue(sName) >>= aTmp;
2213  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFOWNHELP);
2214  m_aRun->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE
2216  m_aRun->append(
2217  OUStringToOString(aTmp, m_rExport.GetCurrentEncoding()));
2218  m_aRun->append('}');
2219  }
2220 
2221  sName = "HelpF1Text";
2222  if (xPropSetInfo->hasPropertyByName(sName))
2223  {
2224  xPropSet->getPropertyValue(sName) >>= aTmp;
2225  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFOWNSTAT);
2226  m_aRun->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE
2228  m_aRun->append(
2229  OUStringToOString(aTmp, m_rExport.GetCurrentEncoding()));
2230  m_aRun->append('}');
2231  }
2232  m_aRun->append("}");
2233  }
2234  else if (xInfo->supportsService("com.sun.star.form.component.ListBox"))
2235  {
2236  OUString aStr;
2237  uno::Sequence<sal_Int16> aIntSeq;
2238  uno::Sequence<OUString> aStrSeq;
2239 
2241  m_rExport.GetCurrentEncoding()));
2242  m_aRun->append(
2244  "{");
2245  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFTYPE "2"); // 2 = list
2246  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFHASLISTBOX);
2247 
2248  xPropSet->getPropertyValue("DefaultSelection") >>= aIntSeq;
2249  if (aIntSeq.hasElements())
2250  {
2251  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFDEFRES);
2252  // a dropdown list can have only one 'selected item by default'
2253  m_aRun->append(static_cast<sal_Int32>(aIntSeq[0]));
2254  }
2255 
2256  xPropSet->getPropertyValue("SelectedItems") >>= aIntSeq;
2257  if (aIntSeq.hasElements())
2258  {
2259  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFRES);
2260  // a dropdown list can have only one 'currently selected item'
2261  m_aRun->append(static_cast<sal_Int32>(aIntSeq[0]));
2262  }
2263 
2264  sName = "Name";
2265  if (xPropSetInfo->hasPropertyByName(sName))
2266  {
2267  xPropSet->getPropertyValue(sName) >>= aStr;
2268  m_aRun->append(
2270  " ");
2271  m_aRun->append(
2272  OUStringToOString(aStr, m_rExport.GetCurrentEncoding()));
2273  m_aRun->append('}');
2274  }
2275 
2276  sName = "HelpText";
2277  if (xPropSetInfo->hasPropertyByName(sName))
2278  {
2279  xPropSet->getPropertyValue(sName) >>= aStr;
2280  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFOWNHELP);
2281  m_aRun->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE
2283  m_aRun->append(
2284  OUStringToOString(aStr, m_rExport.GetCurrentEncoding()));
2285  m_aRun->append('}');
2286  }
2287 
2288  sName = "HelpF1Text";
2289  if (xPropSetInfo->hasPropertyByName(sName))
2290  {
2291  xPropSet->getPropertyValue(sName) >>= aStr;
2292  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFOWNSTAT);
2293  m_aRun->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE
2295  m_aRun->append(
2296  OUStringToOString(aStr, m_rExport.GetCurrentEncoding()));
2297  m_aRun->append('}');
2298  }
2299 
2300  xPropSet->getPropertyValue("StringItemList") >>= aStrSeq;
2301  for (const auto& rStr : std::as_const(aStrSeq))
2302  m_aRun
2303  ->append(
2305  " ")
2306  .append(OUStringToOString(rStr, m_rExport.GetCurrentEncoding()))
2307  .append('}');
2308 
2309  m_aRun->append("}}");
2310 
2311  // field result is empty, ffres already contains the form result
2312  m_aRun->append("}{" OOO_STRING_SVTOOLS_RTF_FLDRSLT " ");
2313  }
2314  else
2315  SAL_INFO("sw.rtf", OSL_THIS_FUNC << " unhandled form control: '"
2316  << xInfo->getImplementationName()
2317  << "'");
2318  m_aRun->append('}');
2319  }
2320  }
2321  }
2322 
2323  m_aRun->append('}');
2324  }
2325  break;
2326  case ww8::Frame::eOle:
2327  {
2328  const SwFrameFormat& rFrameFormat = rFrame.GetFrameFormat();
2329  const SdrObject* pSdrObj = rFrameFormat.FindRealSdrObject();
2330  if (pSdrObj)
2331  {
2332  SwNodeIndex aIdx(*rFrameFormat.GetContent().GetContentIdx(), 1);
2333  SwOLENode& rOLENd = *aIdx.GetNode().GetOLENode();
2334  FlyFrameOLE(dynamic_cast<const SwFlyFrameFormat*>(&rFrameFormat), rOLENd,
2335  rFrame.GetLayoutSize());
2336  }
2337  }
2338  break;
2339  default:
2340  SAL_INFO("sw.rtf", OSL_THIS_FUNC << ": unknown type ("
2341  << static_cast<int>(rFrame.GetWriterType()) << ")");
2342  break;
2343  }
2344 }
2345 
2347 {
2348  switch (rCaseMap.GetValue())
2349  {
2350  case SvxCaseMap::SmallCaps:
2351  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SCAPS);
2352  break;
2353  case SvxCaseMap::Uppercase:
2354  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_CAPS);
2355  break;
2356  default: // Something that rtf does not support
2357  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SCAPS);
2358  m_aStyles.append(sal_Int32(0));
2359  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_CAPS);
2360  m_aStyles.append(sal_Int32(0));
2361  break;
2362  }
2363 }
2364 
2366 {
2367  const Color aColor(rColor.GetValue());
2368 
2369  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_CF);
2370  m_aStyles.append(static_cast<sal_Int32>(m_rExport.GetColor(aColor)));
2371 }
2372 
2374 {
2375  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_OUTL);
2376  if (!rContour.GetValue())
2377  m_aStyles.append(sal_Int32(0));
2378 }
2379 
2381 {
2382  switch (rCrossedOut.GetStrikeout())
2383  {
2384  case STRIKEOUT_NONE:
2385  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_STRIKE);
2386  m_aStyles.append(sal_Int32(0));
2387  break;
2388  case STRIKEOUT_DOUBLE:
2389  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_STRIKED);
2390  m_aStyles.append(sal_Int32(1));
2391  break;
2392  default:
2393  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_STRIKE);
2394  break;
2395  }
2396 }
2397 
2399 {
2400  short nEsc = rEscapement.GetEsc();
2401  short nProp = rEscapement.GetProportionalHeight();
2402  sal_Int32 nProp100 = nProp * 100;
2403  if (DFLT_ESC_PROP == nProp || nProp < 1 || nProp > 100)
2404  {
2405  if (DFLT_ESC_SUB == nEsc || DFLT_ESC_AUTO_SUB == nEsc)
2406  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SUB);
2407  else if (DFLT_ESC_SUPER == nEsc || DFLT_ESC_AUTO_SUPER == nEsc)
2408  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SUPER);
2409  return;
2410  }
2411  if (DFLT_ESC_AUTO_SUPER == nEsc)
2412  {
2413  nEsc = .8 * (100 - nProp);
2414  ++nProp100; // A 1 afterwards means 'automatic' according to editeng/rtf/rtfitem.cxx
2415  }
2416  else if (DFLT_ESC_AUTO_SUB == nEsc)
2417  {
2418  nEsc = .2 * -(100 - nProp);
2419  ++nProp100;
2420  }
2421 
2422  const char* pUpDn;
2423 
2424  double fHeight = m_rExport.GetItem(RES_CHRATR_FONTSIZE).GetHeight();
2425 
2426  if (0 < nEsc)
2427  pUpDn = OOO_STRING_SVTOOLS_RTF_UP;
2428  else if (0 > nEsc)
2429  {
2430  pUpDn = OOO_STRING_SVTOOLS_RTF_DN;
2431  fHeight = -fHeight;
2432  }
2433  else
2434  return;
2435 
2436  m_aStyles.append('{');
2437  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_IGNORE);
2438  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_UPDNPROP);
2439  m_aStyles.append(nProp100);
2440  m_aStyles.append('}');
2441  m_aStyles.append(pUpDn);
2442 
2443  /*
2444  * Calculate the act. FontSize and the percentage of the displacement;
2445  * RTF file expects half points, while internally it's in twips.
2446  * Formally : (FontSize * 1/20 ) pts x * 2
2447  * ----------------------- = ------------
2448  * 100% Escapement
2449  */
2450  m_aStyles.append(static_cast<sal_Int32>(round(fHeight * nEsc / 1000)));
2451 }
2452 
2454 {
2455  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_LOCH);
2456  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_F);
2457  m_aStyles.append(static_cast<sal_Int32>(m_rExport.m_aFontHelper.GetId(rFont)));
2458 
2459  if (!m_rExport.HasItem(RES_CHRATR_CJK_FONT) && !m_rExport.HasItem(RES_CHRATR_CTL_FONT))
2460  {
2461  // Be explicit about that the given font should be used everywhere, not
2462  // just for the loch range.
2463  m_aStylesAssoc.append(OOO_STRING_SVTOOLS_RTF_HICH);
2464  m_aStylesAssoc.append(OOO_STRING_SVTOOLS_RTF_AF);
2465  m_aStylesAssoc.append(static_cast<sal_Int32>(m_rExport.m_aFontHelper.GetId(rFont)));
2466  }
2467 
2468  // FIXME: this may be a tad expensive... but the charset needs to be
2469  // consistent with what wwFont::WriteRtf() does
2470  sw::util::FontMapExport aTmp(rFont.GetFamilyName());
2472  aTmp.msPrimary, aTmp.msSecondary, rFont.GetCharSet());
2473  m_rExport.SetCurrentEncoding(rtl_getTextEncodingFromWindowsCharset(nWindowsCharset));
2474  if (m_rExport.GetCurrentEncoding() == RTL_TEXTENCODING_DONTKNOW)
2475  m_rExport.SetCurrentEncoding(m_rExport.GetDefaultEncoding());
2476 }
2477 
2479 {
2480  switch (rFontSize.Which())
2481  {
2482  case RES_CHRATR_FONTSIZE:
2483  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_FS);
2484  m_aStyles.append(static_cast<sal_Int32>(rFontSize.GetHeight() / 10));
2485  break;
2487  m_aStylesAssoc.append(OOO_STRING_SVTOOLS_RTF_FS);
2488  m_aStylesAssoc.append(static_cast<sal_Int32>(rFontSize.GetHeight() / 10));
2489  break;
2491  m_aStylesAssoc.append(OOO_STRING_SVTOOLS_RTF_AFS);
2492  m_aStylesAssoc.append(static_cast<sal_Int32>(rFontSize.GetHeight() / 10));
2493  break;
2494  }
2495 }
2496 
2498 {
2499  // in quarter points then in twips
2500  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_EXPND);
2501  m_aStyles.append(static_cast<sal_Int32>(rKerning.GetValue() / 5));
2502  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_EXPNDTW);
2503  m_aStyles.append(static_cast<sal_Int32>(rKerning.GetValue()));
2504 }
2505 
2507 {
2508  switch (rLanguage.Which())
2509  {
2510  case RES_CHRATR_LANGUAGE:
2511  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_LANG);
2512  m_aStyles.append(
2513  static_cast<sal_Int32>(static_cast<sal_uInt16>(rLanguage.GetLanguage())));
2514  break;
2516  m_aStylesAssoc.append(OOO_STRING_SVTOOLS_RTF_LANGFE);
2517  m_aStylesAssoc.append(
2518  static_cast<sal_Int32>(static_cast<sal_uInt16>(rLanguage.GetLanguage())));
2519  break;
2521  m_aStylesAssoc.append(OOO_STRING_SVTOOLS_RTF_ALANG);
2522  m_aStylesAssoc.append(
2523  static_cast<sal_Int32>(static_cast<sal_uInt16>(rLanguage.GetLanguage())));
2524  break;
2525  }
2526 }
2527 
2529 {
2530  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_I);
2531  if (rPosture.GetPosture() == ITALIC_NONE)
2532  m_aStyles.append(sal_Int32(0));
2533 }
2534 
2536 {
2537  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SHAD);
2538  if (!rShadow.GetValue())
2539  m_aStyles.append(sal_Int32(0));
2540 }
2541 
2543 {
2544  const char* pStr = nullptr;
2545  const SfxPoolItem* pItem = m_rExport.HasItem(RES_CHRATR_WORDLINEMODE);
2546  bool bWord = false;
2547  if (pItem)
2548  bWord = static_cast<const SvxWordLineModeItem*>(pItem)->GetValue();
2549  switch (rUnderline.GetLineStyle())
2550  {
2551  case LINESTYLE_SINGLE:
2553  break;
2554  case LINESTYLE_DOUBLE:
2556  break;
2557  case LINESTYLE_NONE:
2559  break;
2560  case LINESTYLE_DOTTED:
2562  break;
2563  case LINESTYLE_DASH:
2565  break;
2566  case LINESTYLE_DASHDOT:
2568  break;
2569  case LINESTYLE_DASHDOTDOT:
2571  break;
2572  case LINESTYLE_BOLD:
2574  break;
2575  case LINESTYLE_WAVE:
2577  break;
2578  case LINESTYLE_BOLDDOTTED:
2580  break;
2581  case LINESTYLE_BOLDDASH:
2583  break;
2584  case LINESTYLE_LONGDASH:
2586  break;
2589  break;
2590  case LINESTYLE_BOLDDASHDOT:
2592  break;
2595  break;
2596  case LINESTYLE_BOLDWAVE:
2598  break;
2599  case LINESTYLE_DOUBLEWAVE:
2601  break;
2602  default:
2603  break;
2604  }
2605 
2606  if (pStr)
2607  {
2608  m_aStyles.append(pStr);
2609  // NEEDSWORK looks like here rUnderline.GetColor() is always black,
2610  // even if the color in the odt is for example green...
2611  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ULC);
2612  m_aStyles.append(static_cast<sal_Int32>(m_rExport.GetColor(rUnderline.GetColor())));
2613  }
2614 }
2615 
2617 {
2618  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_B);
2619  if (rWeight.GetWeight() != WEIGHT_BOLD)
2620  m_aStyles.append(sal_Int32(0));
2621 }
2622 
2624 {
2625  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_KERNING);
2626  m_aStyles.append(static_cast<sal_Int32>(rAutoKern.GetValue() ? 1 : 0));
2627 }
2628 
2630 {
2631  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ANIMTEXT);
2632  m_aStyles.append(static_cast<sal_Int32>(rBlink.GetValue() ? 2 : 0));
2633 }
2634 
2636 {
2637  if (!rBrush.GetColor().GetTransparency())
2638  {
2639  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_CHCBPAT);
2640  m_aStyles.append(static_cast<sal_Int32>(m_rExport.GetColor(rBrush.GetColor())));
2641  }
2642 }
2643 
2645 {
2646  m_aStylesAssoc.append(OOO_STRING_SVTOOLS_RTF_DBCH);
2647  m_aStylesAssoc.append(OOO_STRING_SVTOOLS_RTF_AF);
2648  m_aStylesAssoc.append(static_cast<sal_Int32>(m_rExport.m_aFontHelper.GetId(rFont)));
2649 }
2650 
2652 {
2653  CharFontSize(rFontSize);
2654 }
2655 
2657 {
2658  CharLanguage(rLanguageItem);
2659 }
2660 
2662 {
2663  m_aStylesAssoc.append(OOO_STRING_SVTOOLS_RTF_I);
2664  if (rPosture.GetPosture() == ITALIC_NONE)
2665  m_aStylesAssoc.append(sal_Int32(0));
2666 }
2667 
2669 {
2670  m_aStylesAssoc.append(OOO_STRING_SVTOOLS_RTF_B);
2671  if (rWeight.GetWeight() != WEIGHT_BOLD)
2672  m_aStylesAssoc.append(sal_Int32(0));
2673 }
2674 
2676 {
2677  m_aStylesAssoc.append(OOO_STRING_SVTOOLS_RTF_DBCH);
2678  m_aStylesAssoc.append(OOO_STRING_SVTOOLS_RTF_AF);
2679  m_aStylesAssoc.append(static_cast<sal_Int32>(m_rExport.m_aFontHelper.GetId(rFont)));
2680 }
2681 
2683 {
2684  CharFontSize(rFontSize);
2685 }
2686 
2688 {
2689  CharLanguage(rLanguageItem);
2690 }
2691 
2693 {
2694  m_aStylesAssoc.append(OOO_STRING_SVTOOLS_RTF_AI);
2695  if (rPosture.GetPosture() == ITALIC_NONE)
2696  m_aStylesAssoc.append(sal_Int32(0));
2697 }
2698 
2700 {
2701  m_aStylesAssoc.append(OOO_STRING_SVTOOLS_RTF_AB);
2702  if (rWeight.GetWeight() != WEIGHT_BOLD)
2703  m_aStylesAssoc.append(sal_Int32(0));
2704 }
2705 
2707 
2709 
2711 {
2712  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_HORZVERT);
2713  m_aStyles.append(static_cast<sal_Int32>(rRotate.IsFitToLine() ? 1 : 0));
2714 }
2715 
2717 {
2718  FontEmphasisMark v = rEmphasisMark.GetEmphasisMark();
2719  if (v == FontEmphasisMark::NONE)
2720  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ACCNONE);
2721  else if (v == (FontEmphasisMark::Dot | FontEmphasisMark::PosAbove))
2722  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ACCDOT);
2723  else if (v == (FontEmphasisMark::Accent | FontEmphasisMark::PosAbove))
2724  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ACCCOMMA);
2725  else if (v == (FontEmphasisMark::Circle | FontEmphasisMark::PosAbove))
2726  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ACCCIRCLE);
2727  else if (v == (FontEmphasisMark::Dot | FontEmphasisMark::PosBelow))
2728  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ACCUNDERDOT);
2729 }
2730 
2732 {
2733  if (rTwoLines.GetValue())
2734  {
2735  sal_Unicode cStart = rTwoLines.GetStartBracket();
2736  sal_Unicode cEnd = rTwoLines.GetEndBracket();
2737 
2738  sal_uInt16 nType;
2739  if (!cStart && !cEnd)
2740  nType = 0;
2741  else if ('{' == cStart || '}' == cEnd)
2742  nType = 4;
2743  else if ('<' == cStart || '>' == cEnd)
2744  nType = 3;
2745  else if ('[' == cStart || ']' == cEnd)
2746  nType = 2;
2747  else // all other kind of brackets
2748  nType = 1;
2749 
2750  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_TWOINONE);
2751  m_aStyles.append(static_cast<sal_Int32>(nType));
2752  }
2753 }
2754 
2756 {
2757  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_CHARSCALEX);
2758  m_aStyles.append(static_cast<sal_Int32>(rScaleWidth.GetValue()));
2759 }
2760 
2762 {
2763  const char* pStr;
2764  switch (rRelief.GetValue())
2765  {
2766  case FontRelief::Embossed:
2768  break;
2769  case FontRelief::Engraved:
2771  break;
2772  default:
2773  pStr = nullptr;
2774  break;
2775  }
2776 
2777  if (pStr)
2778  m_aStyles.append(pStr);
2779 }
2780 
2782 {
2783  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_V);
2784  if (!rHidden.GetValue())
2785  m_aStyles.append(sal_Int32(0));
2786 }
2787 
2789  const sal_uInt16 nDist, const bool bShadow)
2790 {
2791  m_aStyles.append(
2792  OutBorderLine(m_rExport, pAllBorder, OOO_STRING_SVTOOLS_RTF_CHBRDR, nDist,
2793  bShadow ? SvxShadowLocation::BottomRight : SvxShadowLocation::NONE));
2794 }
2795 
2797 {
2798  if (!rBrush.GetColor().GetTransparency())
2799  {
2800  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_HIGHLIGHT);
2801  m_aStyles.append(static_cast<sal_Int32>(msfilter::util::TransColToIco(rBrush.GetColor())));
2802  }
2803 }
2804 
2806 {
2807  if (!rURL.GetValue().isEmpty())
2808  {
2809  const SwCharFormat* pFormat;
2810  const SwTextINetFormat* pTextAtr = rURL.GetTextINetFormat();
2811 
2812  if (pTextAtr && nullptr != (pFormat = pTextAtr->GetCharFormat()))
2813  {
2814  sal_uInt16 nStyle = m_rExport.GetId(pFormat);
2815  OString* pString = m_rExport.GetStyle(nStyle);
2816  if (pString)
2817  m_aStyles.append(*pString);
2818  }
2819  }
2820 }
2821 
2823 {
2824  sal_uInt16 nStyle = m_rExport.GetId(rCharFormat.GetCharFormat());
2825  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_CS);
2826  m_aStyles.append(static_cast<sal_Int32>(nStyle));
2827  OString* pString = m_rExport.GetStyle(nStyle);
2828  if (pString)
2829  m_aStyles.append(*pString);
2830 }
2831 
2833 {
2834  if (rFootnote.GetNumStr().isEmpty())
2835  m_aRun->append(OOO_STRING_SVTOOLS_RTF_CHFTN);
2836  else
2837  m_aRun->append(
2838  msfilter::rtfutil::OutString(rFootnote.GetNumStr(), m_rExport.GetCurrentEncoding()));
2839 }
2840 
2842 {
2843  SAL_INFO("sw.rtf", OSL_THIS_FUNC << " start");
2844 
2845  m_aRun->append("{" OOO_STRING_SVTOOLS_RTF_SUPER " ");
2846  EndRunProperties(nullptr);
2847  m_aRun->append(' ');
2848  WriteTextFootnoteNumStr(rFootnote);
2850  if (rFootnote.IsEndNote() || m_rExport.m_pDoc->GetFootnoteInfo().m_ePos == FTNPOS_CHAPTER)
2851  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FTNALT);
2852  m_aRun->append(' ');
2853  WriteTextFootnoteNumStr(rFootnote);
2854 
2855  /*
2856  * The footnote contains a whole paragraph, so we have to:
2857  * 1) Reset, then later restore the contents of our run buffer and run state.
2858  * 2) Buffer the output of the whole paragraph, as we do so for section headers already.
2859  */
2860  const SwNodeIndex* pIndex = rFootnote.GetTextFootnote()->GetStartNode();
2861  RtfStringBuffer aRun = m_aRun;
2862  m_aRun.clear();
2863  bool bInRunOrig = m_bInRun;
2864  m_bInRun = false;
2865  bool bSingleEmptyRunOrig = m_bSingleEmptyRun;
2866  m_bSingleEmptyRun = false;
2867  m_bBufferSectionHeaders = true;
2868  m_rExport.WriteSpecialText(pIndex->GetIndex() + 1, pIndex->GetNode().EndOfSectionIndex(),
2869  !rFootnote.IsEndNote() ? TXT_FTN : TXT_EDN);
2870  m_bBufferSectionHeaders = false;
2871  m_bInRun = bInRunOrig;
2872  m_bSingleEmptyRun = bSingleEmptyRunOrig;
2873  m_aRun = aRun;
2874  m_aRun->append(m_aSectionHeaders.makeStringAndClear());
2875 
2876  m_aRun->append("}");
2877  m_aRun->append("}");
2878 
2879  SAL_INFO("sw.rtf", OSL_THIS_FUNC << " end");
2880 }
2881 
2882 void RtfAttributeOutput::ParaLineSpacing_Impl(short nSpace, short nMulti)
2883 {
2884  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SL);
2885  m_aStyles.append(static_cast<sal_Int32>(nSpace));
2886  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SLMULT);
2887  m_aStyles.append(static_cast<sal_Int32>(nMulti));
2888 }
2889 
2891 {
2892  switch (rAdjust.GetAdjust())
2893  {
2894  case SvxAdjust::Left:
2895  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_QL);
2896  break;
2897  case SvxAdjust::Right:
2898  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_QR);
2899  break;
2900  case SvxAdjust::BlockLine:
2901  case SvxAdjust::Block:
2902  if (rAdjust.GetLastBlock() == SvxAdjust::Block)
2903  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_QD);
2904  else
2905  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_QJ);
2906  break;
2907  case SvxAdjust::Center:
2908  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_QC);
2909  break;
2910  default:
2911  break;
2912  }
2913 }
2914 
2916 {
2917  if (!rSplit.GetValue())
2918  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_KEEP);
2919 }
2920 
2922 {
2923  if (rWidows.GetValue())
2924  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_WIDCTLPAR);
2925  else
2926  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_NOWIDCTLPAR);
2927 }
2928 
2930 {
2931  long nOffset = 0;
2932  // Tabs are absolute by default.
2933  if (m_rExport.m_pDoc->getIDocumentSettingAccess().get(
2935  nOffset = m_rExport.GetItem(RES_LR_SPACE).GetTextLeft();
2936 
2937  for (sal_uInt16 n = 0; n < rTabStop.Count(); n++)
2938  {
2939  const SvxTabStop& rTS = rTabStop[n];
2940  if (SvxTabAdjust::Default != rTS.GetAdjustment())
2941  {
2942  const char* pFill = nullptr;
2943  switch (rTS.GetFill())
2944  {
2945  case cDfltFillChar:
2946  break;
2947 
2948  case '.':
2950  break;
2951  case '_':
2953  break;
2954  case '-':
2956  break;
2957  case '=':
2959  break;
2960  default:
2961  break;
2962  }
2963  if (pFill)
2964  m_aStyles.append(pFill);
2965 
2966  const char* pAdjStr = nullptr;
2967  switch (rTS.GetAdjustment())
2968  {
2969  case SvxTabAdjust::Right:
2970  pAdjStr = OOO_STRING_SVTOOLS_RTF_TQR;
2971  break;
2972  case SvxTabAdjust::Decimal:
2973  pAdjStr = OOO_STRING_SVTOOLS_RTF_TQDEC;
2974  break;
2975  case SvxTabAdjust::Center:
2976  pAdjStr = OOO_STRING_SVTOOLS_RTF_TQC;
2977  break;
2978  default:
2979  break;
2980  }
2981  if (pAdjStr)
2982  m_aStyles.append(pAdjStr);
2983  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_TX);
2984  m_aStyles.append(static_cast<sal_Int32>(rTS.GetTabPos() + nOffset));
2985  }
2986  else
2987  {
2988  m_aTabStop.append(OOO_STRING_SVTOOLS_RTF_DEFTAB);
2989  m_aTabStop.append(rTabStop[0].GetTabPos());
2990  }
2991  }
2992 }
2993 
2995 {
2996  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_HYPHPAR);
2997  m_aStyles.append(sal_Int32(rHyphenZone.IsHyphen()));
2998 }
2999 
3000 void RtfAttributeOutput::ParaNumRule_Impl(const SwTextNode* pTextNd, sal_Int32 nLvl,
3001  sal_Int32 nNumId)
3002 {
3003  if (USHRT_MAX == nNumId || 0 == nNumId || nullptr == pTextNd)
3004  return;
3005 
3006  const SwNumRule* pRule = pTextNd->GetNumRule();
3007 
3008  if (!pRule || !pTextNd->IsInList())
3009  return;
3010 
3011  SAL_WARN_IF(pTextNd->GetActualListLevel() < 0 || pTextNd->GetActualListLevel() >= MAXLEVEL,
3012  "sw.rtf", "text node does not have valid list level");
3013 
3014  const SwNumFormat* pFormat = pRule->GetNumFormat(nLvl);
3015  if (!pFormat)
3016  pFormat = &pRule->Get(nLvl);
3017 
3018  const SfxItemSet& rNdSet = pTextNd->GetSwAttrSet();
3019 
3020  m_aStyles.append('{');
3021  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_LISTTEXT);
3022  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_PARD);
3023  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_PLAIN);
3024  m_aStyles.append(' ');
3025 
3026  SvxLRSpaceItem aLR(rNdSet.Get(RES_LR_SPACE));
3027  aLR.SetTextLeft(aLR.GetTextLeft() + pFormat->GetIndentAt());
3028  aLR.SetTextFirstLineOffset(pFormat->GetFirstLineOffset()); //TODO: overflow
3029 
3030  sal_uInt16 nStyle = m_rExport.GetId(pFormat->GetCharFormat());
3031  OString* pString = m_rExport.GetStyle(nStyle);
3032  if (pString)
3033  m_aStyles.append(*pString);
3034 
3035  {
3036  OUString sText;
3037  if (SVX_NUM_CHAR_SPECIAL == pFormat->GetNumberingType()
3038  || SVX_NUM_BITMAP == pFormat->GetNumberingType())
3039  sText = OUString(pFormat->GetBulletChar());
3040  else
3041  sText = pTextNd->GetNumString();
3042 
3043  if (!sText.isEmpty())
3044  {
3045  m_aStyles.append(' ');
3046  m_aStyles.append(msfilter::rtfutil::OutString(sText, m_rExport.GetDefaultEncoding()));
3047  }
3048 
3049  if (OUTLINE_RULE != pRule->GetRuleType())
3050  {
3051  if (!sText.isEmpty())
3052  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_TAB);
3053  m_aStyles.append('}');
3054  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ILVL);
3055  if (nLvl > 8) // RTF knows only 9 levels
3056  {
3057  m_aStyles.append(sal_Int32(8));
3059  m_aStyles.append(nLvl);
3060  m_aStyles.append('}');
3061  }
3062  else
3063  m_aStyles.append(nLvl);
3064  }
3065  else
3066  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_TAB "}");
3067  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_LS);
3068  m_aStyles.append(static_cast<sal_Int32>(m_rExport.GetNumberingId(*pRule)) + 1);
3069  m_aStyles.append(' ');
3070  }
3071  FormatLRSpace(aLR);
3072 }
3073 
3075 {
3076  if (!rScriptSpace.GetValue())
3077  return;
3078 
3079  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ASPALPHA);
3080 }
3081 
3083 {
3084  SAL_INFO("sw.rtf", "TODO: " << OSL_THIS_FUNC);
3085 }
3086 
3088 {
3089  SAL_INFO("sw.rtf", "TODO: " << OSL_THIS_FUNC);
3090 }
3091 
3093 {
3094  const char* pStr;
3095  switch (rAlign.GetValue())
3096  {
3099  break;
3102  break;
3105  break;
3108  break;
3109 
3110  default:
3112  break;
3113  }
3114  m_aStyles.append(pStr);
3115 }
3116 
3118 {
3119  SAL_INFO("sw.rtf", "TODO: " << OSL_THIS_FUNC);
3120 }
3121 
3123 {
3124  if (m_rExport.m_bOutPageDescs)
3125  {
3126  m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_PGWSXN);
3127  m_aSectionBreaks.append(static_cast<sal_Int32>(rSize.GetWidth()));
3128  m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_PGHSXN);
3129  m_aSectionBreaks.append(static_cast<sal_Int32>(rSize.GetHeight()));
3130  if (!m_bBufferSectionBreaks)
3131  m_rExport.Strm().WriteOString(m_aSectionBreaks.makeStringAndClear());
3132  }
3133 }
3134 
3136 {
3137  SAL_INFO("sw.rtf", "TODO: " << OSL_THIS_FUNC);
3138 }
3139 
3141 {
3142  if (!m_rExport.m_bOutFlyFrameAttrs)
3143  {
3144  if (m_rExport.m_bOutPageDescs)
3145  {
3146  if (rLRSpace.GetLeft())
3147  {
3148  m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_MARGLSXN);
3149  m_aSectionBreaks.append(static_cast<sal_Int32>(rLRSpace.GetLeft()));
3150  }
3151  if (rLRSpace.GetRight())
3152  {
3153  m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_MARGRSXN);
3154  m_aSectionBreaks.append(static_cast<sal_Int32>(rLRSpace.GetRight()));
3155  }
3156  if (!m_bBufferSectionBreaks)
3157  m_rExport.Strm().WriteOString(m_aSectionBreaks.makeStringAndClear());
3158  }
3159  else
3160  {
3161  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_LI);
3162  m_aStyles.append(static_cast<sal_Int32>(rLRSpace.GetTextLeft()));
3163  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_RI);
3164  m_aStyles.append(static_cast<sal_Int32>(rLRSpace.GetRight()));
3165  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_LIN);
3166  m_aStyles.append(static_cast<sal_Int32>(rLRSpace.GetTextLeft()));
3167  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_RIN);
3168  m_aStyles.append(static_cast<sal_Int32>(rLRSpace.GetRight()));
3169  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_FI);
3170  m_aStyles.append(static_cast<sal_Int32>(rLRSpace.GetTextFirstLineOffset()));
3171  }
3172  }
3173  else if (m_rExport.GetRTFFlySyntax())
3174  {
3175  // Wrap: top and bottom spacing, convert from twips to EMUs.
3176  m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3177  "dxWrapDistLeft", OString::number(rLRSpace.GetLeft() * 635)));
3178  m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3179  "dxWrapDistRight", OString::number(rLRSpace.GetRight() * 635)));
3180  }
3181 }
3182 
3184 {
3185  if (!m_rExport.m_bOutFlyFrameAttrs)
3186  {
3187  if (m_rExport.m_bOutPageDescs)
3188  {
3189  OSL_ENSURE(m_rExport.GetCurItemSet(), "Impossible");
3190  if (!m_rExport.GetCurItemSet())
3191  return;
3192 
3193  // If we export a follow page format, then our doc model has
3194  // separate header/footer distances for the first page and the
3195  // follow pages, but Word can have only a single distance. In case
3196  // the two values differ, work with the value from the first page
3197  // format to be in sync with the import.
3198  sw::util::HdFtDistanceGlue aDistances(m_rExport.GetFirstPageItemSet()
3199  ? *m_rExport.GetFirstPageItemSet()
3200  : *m_rExport.GetCurItemSet());
3201 
3202  if (aDistances.dyaTop)
3203  {
3204  m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_MARGTSXN);
3205  m_aSectionBreaks.append(static_cast<sal_Int32>(aDistances.dyaTop));
3206  }
3207  if (aDistances.HasHeader())
3208  {
3209  m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_HEADERY);
3210  m_aSectionBreaks.append(static_cast<sal_Int32>(aDistances.dyaHdrTop));
3211  }
3212 
3213  if (aDistances.dyaBottom)
3214  {
3215  m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_MARGBSXN);
3216  m_aSectionBreaks.append(static_cast<sal_Int32>(aDistances.dyaBottom));
3217  }
3218  if (aDistances.HasFooter())
3219  {
3220  m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_FOOTERY);
3221  m_aSectionBreaks.append(static_cast<sal_Int32>(aDistances.dyaHdrBottom));
3222  }
3223  if (!m_bBufferSectionBreaks)
3224  m_rExport.Strm().WriteOString(m_aSectionBreaks.makeStringAndClear());
3225  }
3226  else
3227  {
3228  // Spacing before.
3229  if (m_bParaBeforeAutoSpacing && m_nParaBeforeSpacing == rULSpace.GetUpper())
3230  m_aStyles.append(LO_STRING_SVTOOLS_RTF_SBAUTO "1");
3231  else if (m_bParaBeforeAutoSpacing && m_nParaBeforeSpacing == -1)
3232  {
3233  m_aStyles.append(LO_STRING_SVTOOLS_RTF_SBAUTO "0");
3234  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SB);
3235  m_aStyles.append(static_cast<sal_Int32>(rULSpace.GetUpper()));
3236  }
3237  else
3238  {
3239  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SB);
3240  m_aStyles.append(static_cast<sal_Int32>(rULSpace.GetUpper()));
3241  }
3242  m_bParaBeforeAutoSpacing = false;
3243 
3244  // Spacing after.
3245  if (m_bParaAfterAutoSpacing && m_nParaAfterSpacing == rULSpace.GetLower())
3246  m_aStyles.append(LO_STRING_SVTOOLS_RTF_SAAUTO "1");
3247  else if (m_bParaAfterAutoSpacing && m_nParaAfterSpacing == -1)
3248  {
3249  m_aStyles.append(LO_STRING_SVTOOLS_RTF_SAAUTO "0");
3250  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SA);
3251  m_aStyles.append(static_cast<sal_Int32>(rULSpace.GetLower()));
3252  }
3253  else
3254  {
3255  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SA);
3256  m_aStyles.append(static_cast<sal_Int32>(rULSpace.GetLower()));
3257  }
3258  m_bParaAfterAutoSpacing = false;
3259 
3260  // Contextual spacing.
3261  if (rULSpace.GetContext())
3262  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_CONTEXTUALSPACE);
3263  }
3264  }
3265  else if (m_rExport.GetRTFFlySyntax())
3266  {
3267  // Wrap: top and bottom spacing, convert from twips to EMUs.
3268  m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3269  "dyWrapDistTop", OString::number(rULSpace.GetUpper() * 635)));
3270  m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3271  "dyWrapDistBottom", OString::number(rULSpace.GetLower() * 635)));
3272  }
3273 }
3274 
3276 {
3277  if (m_rExport.m_bOutFlyFrameAttrs && !m_rExport.GetRTFFlySyntax())
3278  {
3279  css::text::WrapTextMode eSurround = rSurround.GetSurround();
3280  bool bGold = css::text::WrapTextMode_DYNAMIC == eSurround;
3281  if (bGold)
3282  eSurround = css::text::WrapTextMode_PARALLEL;
3283  RTFSurround aMC(bGold, static_cast<sal_uInt8>(eSurround));
3284  m_aRunText->append(OOO_STRING_SVTOOLS_RTF_FLYMAINCNT);
3285  m_aRunText->append(static_cast<sal_Int32>(aMC.GetValue()));
3286  }
3287  else if (m_rExport.m_bOutFlyFrameAttrs && m_rExport.GetRTFFlySyntax())
3288  {
3289  // See DocxSdrExport::startDMLAnchorInline() for SwFormatSurround -> WR / WRK mappings.
3290  sal_Int32 nWr = -1;
3291  std::optional<sal_Int32> oWrk;
3292  switch (rSurround.GetValue())
3293  {
3294  case css::text::WrapTextMode_NONE:
3295  nWr = 1; // top and bottom
3296  break;
3297  case css::text::WrapTextMode_THROUGH:
3298  nWr = 3; // none
3299  break;
3300  case css::text::WrapTextMode_PARALLEL:
3301  nWr = 2; // around
3302  oWrk = 0; // both sides
3303  break;
3304  case css::text::WrapTextMode_DYNAMIC:
3305  default:
3306  nWr = 2; // around
3307  oWrk = 3; // largest
3308  break;
3309  }
3310 
3311  if (rSurround.IsContour())
3312  nWr = 4; // tight
3313 
3314  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_SHPWR);
3315  m_rExport.OutLong(nWr);
3316  if (oWrk)
3317  {
3318  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_SHPWRK);
3319  m_rExport.OutLong(*oWrk);
3320  }
3321  }
3322 }
3323 
3325 {
3326  if (m_rExport.m_bOutFlyFrameAttrs && m_rExport.GetRTFFlySyntax())
3327  {
3328  switch (rFlyVert.GetRelationOrient())
3329  {
3330  case text::RelOrientation::PAGE_FRAME:
3331  m_aFlyProperties.push_back(
3332  std::make_pair<OString, OString>("posrelv", OString::number(1)));
3333  break;
3334  default:
3335  m_aFlyProperties.push_back(
3336  std::make_pair<OString, OString>("posrelv", OString::number(2)));
3337  m_rExport.Strm()
3338  .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_SHPBYPARA)
3339  .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_SHPBYIGNORE);
3340  break;
3341  }
3342 
3343  switch (rFlyVert.GetVertOrient())
3344  {
3345  case text::VertOrientation::TOP:
3346  case text::VertOrientation::LINE_TOP:
3347  m_aFlyProperties.push_back(
3348  std::make_pair<OString, OString>("posv", OString::number(1)));
3349  break;
3350  case text::VertOrientation::BOTTOM:
3351  case text::VertOrientation::LINE_BOTTOM:
3352  m_aFlyProperties.push_back(
3353  std::make_pair<OString, OString>("posv", OString::number(3)));
3354  break;
3355  case text::VertOrientation::CENTER:
3356  case text::VertOrientation::LINE_CENTER:
3357  m_aFlyProperties.push_back(
3358  std::make_pair<OString, OString>("posv", OString::number(2)));
3359  break;
3360  default:
3361  break;
3362  }
3363 
3364  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_SHPTOP);
3365  m_rExport.OutLong(rFlyVert.GetPos());
3366  if (m_pFlyFrameSize)
3367  {
3368  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_SHPBOTTOM);
3369  m_rExport.OutLong(rFlyVert.GetPos() + m_pFlyFrameSize->Height());
3370  }
3371  }
3372 }
3373 
3375 {
3376  if (m_rExport.m_bOutFlyFrameAttrs && m_rExport.GetRTFFlySyntax())
3377  {
3378  switch (rFlyHori.GetRelationOrient())
3379  {
3380  case text::RelOrientation::PAGE_FRAME:
3381  m_aFlyProperties.push_back(
3382  std::make_pair<OString, OString>("posrelh", OString::number(1)));
3383  break;
3384  default:
3385  m_aFlyProperties.push_back(
3386  std::make_pair<OString, OString>("posrelh", OString::number(2)));
3387  m_rExport.Strm()
3388  .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_SHPBXCOLUMN)
3389  .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_SHPBXIGNORE);
3390  break;
3391  }
3392 
3393  switch (rFlyHori.GetHoriOrient())
3394  {
3395  case text::HoriOrientation::LEFT:
3396  m_aFlyProperties.push_back(
3397  std::make_pair<OString, OString>("posh", OString::number(1)));
3398  break;
3399  case text::HoriOrientation::CENTER:
3400  m_aFlyProperties.push_back(
3401  std::make_pair<OString, OString>("posh", OString::number(2)));
3402  break;
3403  case text::HoriOrientation::RIGHT:
3404  m_aFlyProperties.push_back(
3405  std::make_pair<OString, OString>("posh", OString::number(3)));
3406  break;
3407  default:
3408  break;
3409  }
3410 
3411  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_SHPLEFT);
3412  m_rExport.OutLong(rFlyHori.GetPos());
3413  if (m_pFlyFrameSize)
3414  {
3415  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_SHPRIGHT);
3416  m_rExport.OutLong(rFlyHori.GetPos() + m_pFlyFrameSize->Width());
3417  }
3418  }
3419 }
3420 
3422 {
3423  if (!m_rExport.GetRTFFlySyntax())
3424  {
3425  RndStdIds eId = rAnchor.GetAnchorId();
3426  m_aRunText->append(OOO_STRING_SVTOOLS_RTF_FLYANCHOR);
3427  m_aRunText->append(static_cast<sal_Int32>(eId));
3428  switch (eId)
3429  {
3430  case RndStdIds::FLY_AT_PAGE:
3431  m_aRunText->append(OOO_STRING_SVTOOLS_RTF_FLYPAGE);
3432  m_aRunText->append(static_cast<sal_Int32>(rAnchor.GetPageNum()));
3433  break;
3434  case RndStdIds::FLY_AT_PARA:
3435  case RndStdIds::FLY_AS_CHAR:
3436  m_aRunText->append(OOO_STRING_SVTOOLS_RTF_FLYCNTNT);
3437  break;
3438  default:
3439  break;
3440  }
3441  }
3442 }
3443 
3445 {
3446  if (m_rExport.GetRTFFlySyntax())
3447  {
3448  const Color& rColor = rBrush.GetColor();
3449  // We in fact need RGB to BGR, but the transformation is symmetric.
3450  m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3451  "fillColor", OString::number(wwUtility::RGBToBGR(rColor))));
3452  }
3453  else if (!rBrush.GetColor().GetTransparency())
3454  {
3455  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_CBPAT);
3456  m_aStyles.append(static_cast<sal_Int32>(m_rExport.GetColor(rBrush.GetColor())));
3457  }
3458 }
3459 
3461 {
3462  m_oFillStyle = rFillStyle.GetValue();
3463 }
3464 
3466 {
3467  if (*m_oFillStyle == drawing::FillStyle_GRADIENT)
3468  {
3469  m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3470  "fillType", OString::number(7))); // Shade using the fillAngle
3471 
3472  const XGradient& rGradient = rFillGradient.GetGradientValue();
3473  const Color& rStartColor = rGradient.GetStartColor();
3474  m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3475  "fillBackColor", OString::number(wwUtility::RGBToBGR(rStartColor))));
3476 
3477  const Color& rEndColor = rGradient.GetEndColor();
3478  m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3479  "fillColor", OString::number(wwUtility::RGBToBGR(rEndColor))));
3480 
3481  switch (rGradient.GetGradientStyle())
3482  {
3483  case css::awt::GradientStyle_LINEAR:
3484  break;
3485  case css::awt::GradientStyle_AXIAL:
3486  m_aFlyProperties.push_back(
3487  std::make_pair<OString, OString>("fillFocus", OString::number(50)));
3488  break;
3489  case css::awt::GradientStyle_RADIAL:
3490  case css::awt::GradientStyle_ELLIPTICAL:
3491  case css::awt::GradientStyle_SQUARE:
3492  case css::awt::GradientStyle_RECT:
3493  default:
3494  break;
3495  }
3496  }
3497 }
3498 
3500 {
3501  static const SvxBoxItemLine aBorders[] = { SvxBoxItemLine::TOP, SvxBoxItemLine::LEFT,
3502  SvxBoxItemLine::BOTTOM, SvxBoxItemLine::RIGHT };
3503  static const char* aBorderNames[]
3506 
3507  sal_uInt16 const nDist = rBox.GetSmallestDistance();
3508 
3509  if (m_rExport.GetRTFFlySyntax())
3510  {
3511  // Borders: spacing to contents, convert from twips to EMUs.
3512  m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3513  "dxTextLeft", OString::number(rBox.GetDistance(SvxBoxItemLine::LEFT) * 635)));
3514  m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3515  "dyTextTop", OString::number(rBox.GetDistance(SvxBoxItemLine::TOP) * 635)));
3516  m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3517  "dxTextRight", OString::number(rBox.GetDistance(SvxBoxItemLine::RIGHT) * 635)));
3518  m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3519  "dyTextBottom", OString::number(rBox.GetDistance(SvxBoxItemLine::BOTTOM) * 635)));
3520 
3521  const editeng::SvxBorderLine* pLeft = rBox.GetLine(SvxBoxItemLine::LEFT);
3522  const editeng::SvxBorderLine* pRight = rBox.GetLine(SvxBoxItemLine::RIGHT);
3523  const editeng::SvxBorderLine* pTop = rBox.GetLine(SvxBoxItemLine::TOP);
3524  const editeng::SvxBorderLine* pBottom = rBox.GetLine(SvxBoxItemLine::BOTTOM);
3525  if (pLeft && pRight && pTop && pBottom && *pLeft == *pRight && *pLeft == *pTop
3526  && *pLeft == *pBottom)
3527  {
3528  const Color& rColor = pTop->GetColor();
3529  // We in fact need RGB to BGR, but the transformation is symmetric.
3530  m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3531  "lineColor", OString::number(wwUtility::RGBToBGR(rColor))));
3532 
3533  if (pTop->GetBorderLineStyle() != SvxBorderLineStyle::NONE)
3534  {
3535  double const fConverted(editeng::ConvertBorderWidthToWord(
3536  pTop->GetBorderLineStyle(), pTop->GetWidth()));
3537  sal_Int32 nWidth = fConverted * 635; // Twips -> EMUs
3538  m_aFlyProperties.push_back(
3539  std::make_pair<OString, OString>("lineWidth", OString::number(nWidth)));
3540  }
3541  else
3542  // No border: no line.
3543  m_aFlyProperties.push_back(std::make_pair<OString, OString>("fLine", "0"));
3544  }
3545 
3546  return;
3547  }
3548 
3549  if (rBox.GetTop() && rBox.GetBottom() && rBox.GetLeft() && rBox.GetRight()
3550  && *rBox.GetTop() == *rBox.GetBottom() && *rBox.GetTop() == *rBox.GetLeft()
3551  && *rBox.GetTop() == *rBox.GetRight() && nDist == rBox.GetDistance(SvxBoxItemLine::TOP)
3552  && nDist == rBox.GetDistance(SvxBoxItemLine::LEFT)
3553  && nDist == rBox.GetDistance(SvxBoxItemLine::BOTTOM)
3554  && nDist == rBox.GetDistance(SvxBoxItemLine::RIGHT))
3555  m_aSectionBreaks.append(
3556  OutBorderLine(m_rExport, rBox.GetTop(), OOO_STRING_SVTOOLS_RTF_BOX, nDist));
3557  else
3558  {
3559  SvxShadowLocation eShadowLocation = SvxShadowLocation::NONE;
3560  if (const SfxPoolItem* pItem = GetExport().HasItem(RES_SHADOW))
3561  eShadowLocation = static_cast<const SvxShadowItem*>(pItem)->GetLocation();
3562 
3563  const SvxBoxItemLine* pBrd = aBorders;
3564  const char** pBrdNms = aBorderNames;
3565  for (int i = 0; i < 4; ++i, ++pBrd, ++pBrdNms)
3566  {
3567  if (const editeng::SvxBorderLine* pLn = rBox.GetLine(*pBrd))
3568  {
3569  m_aSectionBreaks.append(OutBorderLine(m_rExport, pLn, *pBrdNms,
3570  rBox.GetDistance(*pBrd), eShadowLocation));
3571  }
3572  }
3573  }
3574 
3575  if (!m_bBufferSectionBreaks)
3576  m_aStyles.append(m_aSectionBreaks.makeStringAndClear());
3577 }
3578 
3579 void RtfAttributeOutput::FormatColumns_Impl(sal_uInt16 nCols, const SwFormatCol& rCol, bool bEven,
3580  SwTwips nPageSize)
3581 {
3582  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_COLS);
3583  m_rExport.OutLong(nCols);
3584 
3585  if (rCol.GetLineAdj() != COLADJ_NONE)
3586  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_LINEBETCOL);
3587 
3588  if (bEven)
3589  {
3590  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_COLSX);
3591  m_rExport.OutLong(rCol.GetGutterWidth(true));
3592  }
3593  else
3594  {
3595  const SwColumns& rColumns = rCol.GetColumns();
3596  for (sal_uInt16 n = 0; n < nCols;)
3597  {
3598  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_COLNO);
3599  m_rExport.OutLong(n + 1);
3600 
3601  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_COLW);
3602  m_rExport.OutLong(rCol.CalcPrtColWidth(n, nPageSize));
3603 
3604  if (++n != nCols)
3605  {
3606  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_COLSR);
3607  m_rExport.OutLong(rColumns[n - 1].GetRight() + rColumns[n].GetLeft());
3608  }
3609  }
3610  }
3611 }
3612 
3614 {
3615  if (rItem.GetValue())
3616  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_KEEPN);
3617 }
3618 
3620 {
3621  SAL_INFO("sw.rtf", "TODO: " << OSL_THIS_FUNC);
3622 }
3623 
3625 {
3626  if (!rNumbering.IsCount())
3627  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_NOLINE);
3628 }
3629 
3631 {
3632  SvxFrameDirection nDir = rDirection.GetValue();
3633  if (nDir == SvxFrameDirection::Environment)
3634  nDir = GetExport().GetDefaultFrameDirection();
3635 
3636  if (m_rExport.m_bOutPageDescs)
3637  {
3638  if (nDir == SvxFrameDirection::Vertical_RL_TB)
3639  {
3640  m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_STEXTFLOW);
3641  m_aSectionBreaks.append(static_cast<sal_Int32>(1));
3642  if (!m_bBufferSectionBreaks)
3643  m_rExport.Strm().WriteOString(m_aSectionBreaks.makeStringAndClear());
3644  }
3645  return;
3646  }
3647 
3648  if (m_rExport.GetRTFFlySyntax())
3649  {
3650  if (nDir == SvxFrameDirection::Vertical_RL_TB)
3651  {
3652  // Top to bottom non-ASCII font
3653  m_aFlyProperties.push_back(std::make_pair<OString, OString>("txflTextFlow", "3"));
3654  }
3655  else if (rDirection.GetValue() == SvxFrameDirection::Vertical_LR_BT)
3656  {
3657  // Bottom to top non-ASCII font
3658  m_aFlyProperties.push_back(std::make_pair<OString, OString>("txflTextFlow", "2"));
3659  }
3660  return;
3661  }
3662 
3663  if (nDir == SvxFrameDirection::Horizontal_RL_TB)
3664  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_RTLPAR);
3665  else
3666  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_LTRPAR);
3667 }
3668 
3670 {
3671  const std::map<OUString, css::uno::Any>& rMap = rItem.GetGrabBag();
3672  for (const auto& rValue : rMap)
3673  {
3674  if (rValue.first == "ParaTopMarginBeforeAutoSpacing")
3675  {
3676  m_bParaBeforeAutoSpacing = true;
3677  rValue.second >>= m_nParaBeforeSpacing;
3678  m_nParaBeforeSpacing = convertMm100ToTwip(m_nParaBeforeSpacing);
3679  }
3680  else if (rValue.first == "ParaBottomMarginAfterAutoSpacing")
3681  {
3682  m_bParaAfterAutoSpacing = true;
3683  rValue.second >>= m_nParaAfterSpacing;
3684  m_nParaAfterSpacing = convertMm100ToTwip(m_nParaAfterSpacing);
3685  }
3686  }
3687 }
3688 
3690 
3692 
3694 {
3695  OUString sCmd; // for optional Parameters
3696  switch (pField->GetTyp()->Which())
3697  {
3698  //#i119803# Export user field for RTF filter
3699  case SwFieldIds::User:
3700  sCmd = pField->GetTyp()->GetName();
3701  m_rExport.OutputField(pField, ww::eNONE, sCmd);
3702  break;
3703  default:
3704  m_rExport.OutputField(pField, ww::eUNKNOWN, sCmd);
3705  break;
3706  }
3707 }
3708 
3709 void RtfAttributeOutput::RefField(const SwField& /*rField*/, const OUString& /*rRef*/)
3710 {
3711  SAL_INFO("sw.rtf", "TODO: " << OSL_THIS_FUNC);
3712 }
3713 
3715 {
3716  SAL_INFO("sw.rtf", "TODO: " << OSL_THIS_FUNC);
3717 }
3718 
3719 void RtfAttributeOutput::SetField(const SwField& /*rField*/, ww::eField /*eType*/,
3720  const OUString& /*rCmd*/)
3721 {
3722  SAL_INFO("sw.rtf", "TODO: " << OSL_THIS_FUNC);
3723 }
3724 
3726 {
3727  const SwPostItField& rPField = *static_cast<const SwPostItField*>(pField);
3728 
3729  OString aName = OUStringToOString(rPField.GetName(), RTL_TEXTENCODING_UTF8);
3730  auto it = m_rOpenedAnnotationMarksIds.find(aName);
3731  if (it != m_rOpenedAnnotationMarksIds.end())
3732  {
3733  // In case this field is inside annotation marks, we want to write the
3734  // annotation itself after the annotation mark is closed, not here.
3735  m_aPostitFields[it->second] = &rPField;
3736  return;
3737  }
3738 
3739  m_aRunText->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_ATNID " ");
3740  m_aRunText->append(OUStringToOString(rPField.GetInitials(), m_rExport.GetCurrentEncoding()));
3741  m_aRunText->append("}");
3743  m_aRunText->append(OUStringToOString(rPField.GetPar1(), m_rExport.GetCurrentEncoding()));
3744  m_aRunText->append("}");
3745  m_aRunText->append(OOO_STRING_SVTOOLS_RTF_CHATN);
3746 
3748 
3749  if (m_nCurrentAnnotationMarkId != -1)
3750  {
3752  m_aRunText->append(m_nCurrentAnnotationMarkId);
3753  m_aRunText->append('}');
3754  }
3756  m_aRunText->append(static_cast<sal_Int32>(sw::ms::DateTime2DTTM(rPField.GetDateTime())));
3757  m_aRunText->append('}');
3758  if (const OutlinerParaObject* pObject = rPField.GetTextObject())
3759  m_rExport.SdrExporter().WriteOutliner(*pObject, TXT_ATN);
3760  m_aRunText->append('}');
3761 }
3762 
3764 {
3765  // this is handled in OutputFlyFrame_Impl()
3766  return true;
3767 }
3768 
3770 {
3771  m_aRunText->append("{" OOO_STRING_SVTOOLS_RTF_FIELD
3773  " MACROBUTTON None ");
3774  RunText(pField->GetPar1());
3775  m_aRunText->append("}}");
3776  return false; // do not expand
3777 }
3778 
3780  : AttributeOutputBase("") // ConvertURL isn't used now in RTF output
3781  , m_rExport(rExport)
3782  , m_pPrevPageDesc(nullptr)
3783  , m_nStyleId(0)
3784  , m_nListId(0)
3785  , m_bIsRTL(false)
3786  , m_nScript(i18n::ScriptType::LATIN)
3787  , m_bControlLtrRtl(false)
3788  , m_nNextAnnotationMarkId(0)
3789  , m_nCurrentAnnotationMarkId(-1)
3790  , m_bTableCellOpen(false)
3791  , m_nTableDepth(0)
3792  , m_bTableAfterCell(false)
3793  , m_nColBreakNeeded(false)
3794  , m_bBufferSectionBreaks(false)
3795  , m_bBufferSectionHeaders(false)
3796  , m_bLastTable(true)
3797  , m_bWroteCellInfo(false)
3798  , m_bTableRowEnded(false)
3799  , m_bIsBeforeFirstParagraph(true)
3800  , m_bSingleEmptyRun(false)
3801  , m_bInRun(false)
3802  , m_pFlyFrameSize(nullptr)
3803  , m_bParaBeforeAutoSpacing(false)
3804  , m_nParaBeforeSpacing(0)
3805  , m_bParaAfterAutoSpacing(false)
3806  , m_nParaAfterSpacing(0)
3807 {
3808 }
3809 
3811 
3813 
3814 // These are used by wwFont::WriteRtf()
3815 
3817 void RtfAttributeOutput::StartFont(const OUString& rFamilyName) const
3818 {
3819  // write the font name hex-encoded, but without Unicode - Word at least
3820  // cannot read *both* Unicode and fallback as written by OutString
3822  msfilter::rtfutil::OutString(rFamilyName, m_rExport.GetCurrentEncoding(), false).getStr());
3823 }
3824 
3827 {
3828  m_rExport.Strm().WriteCharPtr(";}");
3830 }
3831 
3833 void RtfAttributeOutput::FontAlternateName(const OUString& rName) const
3834 {
3835  m_rExport.Strm()
3836  .WriteChar('{')
3839  .WriteChar(' ');
3840  // write the font name hex-encoded, but without Unicode - Word at least
3841  // cannot read *both* Unicode and fallback as written by OutString
3842  m_rExport.Strm()
3843  .WriteCharPtr(
3844  msfilter::rtfutil::OutString(rName, m_rExport.GetCurrentEncoding(), false).getStr())
3845  .WriteChar('}');
3846 }
3847 
3850 {
3852  m_rExport.OutULong(nCharSet);
3853  m_rExport.Strm().WriteChar(' ');
3854  m_rExport.SetCurrentEncoding(rtl_getTextEncodingFromWindowsCharset(nCharSet));
3855 }
3856 
3858 void RtfAttributeOutput::FontFamilyType(FontFamily eFamily, const wwFont& rFont) const
3859 {
3861 
3862  const char* pStr = OOO_STRING_SVTOOLS_RTF_FNIL;
3863  switch (eFamily)
3864  {
3865  case FAMILY_ROMAN:
3867  break;
3868  case FAMILY_SWISS:
3870  break;
3871  case FAMILY_MODERN:
3873  break;
3874  case FAMILY_SCRIPT:
3876  break;
3877  case FAMILY_DECORATIVE:
3879  break;
3880  default:
3881  break;
3882  }
3883  m_rExport.OutULong(m_rExport.m_aFontHelper.GetId(rFont)).WriteCharPtr(pStr);
3884 }
3885 
3888 {
3890 
3891  sal_uInt16 nVal = 0;
3892  switch (ePitch)
3893  {
3894  case PITCH_FIXED:
3895  nVal = 1;
3896  break;
3897  case PITCH_VARIABLE:
3898  nVal = 2;
3899  break;
3900  default:
3901  break;
3902  }
3903  m_rExport.OutULong(nVal);
3904 }
3905 
3906 static void lcl_AppendSP(OStringBuffer& rBuffer, const char cName[], const OUString& rValue,
3907  const RtfExport& rExport)
3908 {
3909  rBuffer.append("{" OOO_STRING_SVTOOLS_RTF_SP "{"); // "{\sp{"
3910  rBuffer.append(OOO_STRING_SVTOOLS_RTF_SN " "); //" \sn "
3911  rBuffer.append(cName); //"PropName"
3912  rBuffer.append("}{" OOO_STRING_SVTOOLS_RTF_SV " ");
3913  // "}{ \sv "
3914  rBuffer.append(msfilter::rtfutil::OutString(rValue, rExport.GetCurrentEncoding()));
3915  rBuffer.append("}}");
3916 }
3917 
3918 static OString ExportPICT(const SwFlyFrameFormat* pFlyFrameFormat, const Size& rOrig,
3919  const Size& rRendered, const Size& rMapped, const SwCropGrf& rCr,
3920  const char* pBLIPType, const sal_uInt8* pGraphicAry, sal_uInt64 nSize,
3921  const RtfExport& rExport, SvStream* pStream = nullptr,
3922  bool bWritePicProp = true, const SwAttrSet* pAttrSet = nullptr)
3923 {
3924  OStringBuffer aRet;
3925  if (pBLIPType && nSize && pGraphicAry)
3926  {
3927  bool bIsWMF = std::strcmp(pBLIPType, OOO_STRING_SVTOOLS_RTF_WMETAFILE) == 0;
3928 
3929  aRet.append("{" OOO_STRING_SVTOOLS_RTF_PICT);
3930 
3931  if (pFlyFrameFormat && bWritePicProp)
3932  {
3933  OUString sDescription = pFlyFrameFormat->GetObjDescription();
3934  //write picture properties - wzDescription at first
3935  //looks like: "{\*\picprop{\sp{\sn PropertyName}{\sv PropertyValue}}}"
3936  aRet.append(
3938  lcl_AppendSP(aRet, "wzDescription", sDescription, rExport);
3939  OUString sName = pFlyFrameFormat->GetObjTitle();
3940  lcl_AppendSP(aRet, "wzName", sName, rExport);
3941 
3942  if (pAttrSet)
3943  {
3944  MirrorGraph eMirror = pAttrSet->Get(RES_GRFATR_MIRRORGRF).GetValue();
3945  if (eMirror == MirrorGraph::Vertical || eMirror == MirrorGraph::Both)
3946  // Mirror on the vertical axis is a horizontal flip.
3947  lcl_AppendSP(aRet, "fFlipH", "1", rExport);
3948  }
3949 
3950  aRet.append("}"); //"}"
3951  }
3952 
3953  long nXCroppedSize = rOrig.Width() - (rCr.GetLeft() + rCr.GetRight());
3954  long nYCroppedSize = rOrig.Height() - (rCr.GetTop() + rCr.GetBottom());
3955  /* Graphic with a zero height or width, typically copied from webpages, caused crashes. */
3956  if (!nXCroppedSize)
3957  nXCroppedSize = 100;
3958  if (!nYCroppedSize)
3959  nYCroppedSize = 100;
3960 
3961  //Given the original size and taking cropping into account
3962  //first, how much has the original been scaled to get the
3963  //final rendered size
3964  aRet.append(OOO_STRING_SVTOOLS_RTF_PICSCALEX);
3965  aRet.append(static_cast<sal_Int32>((100 * rRendered.Width()) / nXCroppedSize));
3966  aRet.append(OOO_STRING_SVTOOLS_RTF_PICSCALEY);
3967  aRet.append(static_cast<sal_Int32>((100 * rRendered.Height()) / nYCroppedSize));
3968 
3969  aRet.append(OOO_STRING_SVTOOLS_RTF_PICCROPL);
3970  aRet.append(rCr.GetLeft());
3971  aRet.append(OOO_STRING_SVTOOLS_RTF_PICCROPR);
3972  aRet.append(rCr.GetRight());
3973  aRet.append(OOO_STRING_SVTOOLS_RTF_PICCROPT);
3974  aRet.append(rCr.GetTop());
3975  aRet.append(OOO_STRING_SVTOOLS_RTF_PICCROPB);
3976  aRet.append(rCr.GetBottom());
3977 
3978  aRet.append(OOO_STRING_SVTOOLS_RTF_PICW);
3979  aRet.append(static_cast<sal_Int32>(rMapped.Width()));
3980  aRet.append(OOO_STRING_SVTOOLS_RTF_PICH);
3981  aRet.append(static_cast<sal_Int32>(rMapped.Height()));
3982 
3983  aRet.append(OOO_STRING_SVTOOLS_RTF_PICWGOAL);
3984  aRet.append(static_cast<sal_Int32>(rOrig.Width()));
3985  aRet.append(OOO_STRING_SVTOOLS_RTF_PICHGOAL);
3986  aRet.append(static_cast<sal_Int32>(rOrig.Height()));
3987 
3988  aRet.append(pBLIPType);
3989  if (bIsWMF)
3990  {
3991  aRet.append(sal_Int32(8));
3992  msfilter::rtfutil::StripMetafileHeader(pGraphicAry, nSize);
3993  }
3994  aRet.append(SAL_NEWLINE_STRING);
3995  if (pStream)
3996  pStream->WriteOString(aRet.makeStringAndClear());
3997  if (pStream)
3998  msfilter::rtfutil::WriteHex(pGraphicAry, nSize, pStream);
3999  else
4000  aRet.append(msfilter::rtfutil::WriteHex(pGraphicAry, nSize));
4001  aRet.append('}');
4002  if (pStream)
4003  pStream->WriteOString(aRet.makeStringAndClear());
4004  }
4005  return aRet.makeStringAndClear();
4006 }
4007 
4009  SwOLENode& rOLENode, const Size& rSize)
4010 {
4012  Size aSize(rOLENode.GetTwipSize());
4013  Size aRendered(aSize);
4014  aRendered.setWidth(rSize.Width());
4015  aRendered.setHeight(rSize.Height());
4016  const Graphic* pGraphic = rOLENode.GetGraphic();
4017  Size aMapped(pGraphic->GetPrefSize());
4018  auto& rCr = static_cast<const SwCropGrf&>(rOLENode.GetAttr(RES_GRFATR_CROPGRF));
4019  const char* pBLIPType = OOO_STRING_SVTOOLS_RTF_PNGBLIP;
4020  const sal_uInt8* pGraphicAry = nullptr;
4021  SvMemoryStream aStream;
4022  if (GraphicConverter::Export(aStream, *pGraphic, ConvertDataFormat::PNG) != ERRCODE_NONE)
4023  SAL_WARN("sw.rtf", "failed to export the graphic");
4024  sal_uInt32 nSize = aStream.TellEnd();
4025  pGraphicAry = static_cast<sal_uInt8 const*>(aStream.GetData());
4026  m_aRunText->append(ExportPICT(pFlyFrameFormat, aSize, aRendered, aMapped, rCr, pBLIPType,
4027  pGraphicAry, nSize, m_rExport));
4028  m_aRunText->append("}"); // shppict
4031  SvMemoryStream aWmfStream;
4032  if (GraphicConverter::Export(aWmfStream, *pGraphic, ConvertDataFormat::WMF) != ERRCODE_NONE)
4033  SAL_WARN("sw.rtf", "failed to export the graphic");
4034  nSize = aWmfStream.TellEnd();
4035  pGraphicAry = static_cast<sal_uInt8 const*>(aWmfStream.GetData());
4036  m_aRunText->append(ExportPICT(pFlyFrameFormat, aSize, aRendered, aMapped, rCr, pBLIPType,
4037  pGraphicAry, nSize, m_rExport));
4038  m_aRunText->append("}"); // nonshppict
4039 }
4040 
4042  SwOLENode& rOLENode, const Size& rSize)
4043 {
4044  uno::Reference<embed::XEmbeddedObject> xObj(rOLENode.GetOLEObj().GetOleRef());
4045  sal_Int64 nAspect = rOLENode.GetAspect();
4046  svt::EmbeddedObjectRef aObjRef(xObj, nAspect);
4047  SvGlobalName aObjName(aObjRef->getClassID());
4048 
4049  if (!SotExchange::IsMath(aObjName))
4050  return false;
4051 
4053  uno::Reference<util::XCloseable> xClosable = xObj->getComponent();
4054  if (!xClosable.is())
4055  return false;
4056  // gcc4.4 (and 4.3 and possibly older) have a problem with dynamic_cast directly to the target class,
4057  // so help it with an intermediate cast. I'm not sure what exactly the problem is, seems to be unrelated
4058  // to RTLD_GLOBAL, so most probably a gcc bug.
4059  auto pBase
4060  = dynamic_cast<oox::FormulaExportBase*>(dynamic_cast<SfxBaseModel*>(xClosable.get()));
4061  assert(pBase != nullptr);
4062  OStringBuffer aBuf;
4063  if (pBase)
4064  pBase->writeFormulaRtf(aBuf, m_rExport.GetCurrentEncoding());
4065  m_aRunText->append(aBuf.makeStringAndClear());
4066  // Replacement graphic.
4068  FlyFrameOLEReplacement(pFlyFrameFormat, rOLENode, rSize);
4069  m_aRunText->append("}"); // mmathPict
4070  m_aRunText->append("}"); // mmath
4071 
4072  return true;
4073 }
4074 
4075 void RtfAttributeOutput::FlyFrameOLE(const SwFlyFrameFormat* pFlyFrameFormat, SwOLENode& rOLENode,
4076  const Size& rSize)
4077 {
4078  if (FlyFrameOLEMath(pFlyFrameFormat, rOLENode, rSize))
4079  return;
4080 
4081  FlyFrameOLEReplacement(pFlyFrameFormat, rOLENode, rSize);
4082 }
4083 
4085  const SwGrfNode* pGrfNode)
4086 {
4087  SvMemoryStream aStream;
4088  const sal_uInt8* pGraphicAry = nullptr;
4089  sal_uInt32 nSize = 0;
4090 
4091  const Graphic& rGraphic(pGrfNode->GetGrf());
4092 
4093  // If there is no graphic there is not much point in parsing it
4094  if (rGraphic.GetType() == GraphicType::NONE)
4095  return;
4096 
4097  ConvertDataFormat aConvertDestinationFormat = ConvertDataFormat::WMF;
4098  const char* pConvertDestinationBLIPType = OOO_STRING_SVTOOLS_RTF_WMETAFILE;
4099 
4100  GfxLink aGraphicLink;
4101  const char* pBLIPType = nullptr;
4102  if (rGraphic.IsGfxLink())
4103  {
4104  aGraphicLink = rGraphic.GetGfxLink();
4105  nSize = aGraphicLink.GetDataSize();
4106  pGraphicAry = aGraphicLink.GetData();
4107  switch (aGraphicLink.GetType())
4108  {
4109  // #i15508# trying to add BMP type for better exports, need to check if this works
4110  // checked, does not work. Also need to reset pGraphicAry to NULL to force conversion
4111  // to PNG, else the BMP array will be used.
4112  // It may work using direct DIB data, but that needs to be checked eventually
4113  //
4114  // #i15508# before GfxLinkType::NativeBmp was added the graphic data
4115  // (to be hold in pGraphicAry) was not available; thus for now to stay
4116  // compatible, keep it that way by assigning NULL value to pGraphicAry
4117  case GfxLinkType::NativeBmp:
4118  // pBLIPType = OOO_STRING_SVTOOLS_RTF_WBITMAP;
4119  pGraphicAry = nullptr;
4120  break;
4121 
4122  case GfxLinkType::NativeJpg:
4123  pBLIPType = OOO_STRING_SVTOOLS_RTF_JPEGBLIP;
4124  break;
4125  case GfxLinkType::NativePng:
4126  pBLIPType = OOO_STRING_SVTOOLS_RTF_PNGBLIP;
4127  break;
4128  case GfxLinkType::NativeWmf:
4129  pBLIPType = aGraphicLink.IsEMF() ? OOO_STRING_SVTOOLS_RTF_EMFBLIP
4131  break;
4132  case GfxLinkType::NativeGif:
4133  // GIF is not supported by RTF, but we override default conversion to WMF, PNG seems fits better here.
4134  aConvertDestinationFormat = ConvertDataFormat::PNG;
4135  pConvertDestinationBLIPType = OOO_STRING_SVTOOLS_RTF_PNGBLIP;
4136  break;
4137  default:
4138  break;
4139  }
4140  }
4141 
4142  GraphicType eGraphicType = rGraphic.GetType();
4143  if (!pGraphicAry)
4144  {
4145  if (ERRCODE_NONE
4146  == GraphicConverter::Export(aStream, rGraphic,
4147  (eGraphicType == GraphicType::Bitmap)
4148  ? ConvertDataFormat::PNG
4149  : ConvertDataFormat::WMF))
4150  {
4151  pBLIPType = (eGraphicType == GraphicType::Bitmap) ? OOO_STRING_SVTOOLS_RTF_PNGBLIP
4153  nSize = aStream.TellEnd();
4154  pGraphicAry = static_cast<sal_uInt8 const*>(aStream.GetData());
4155  }
4156  }
4157 
4158  Size aMapped(eGraphicType == GraphicType::Bitmap ? rGraphic.GetSizePixel()
4159  : rGraphic.GetPrefSize());
4160 
4161  auto& rCr = static_cast<const SwCropGrf&>(pGrfNode->GetAttr(RES_GRFATR_CROPGRF));
4162 
4163  //Get original size in twips
4164  Size aSize(pGrfNode->GetTwipSize());
4165  Size aRendered(aSize);
4166 
4167  const SwFormatFrameSize& rS = pFlyFrameFormat->GetFrameSize();
4168  aRendered.setWidth(rS.GetWidth());
4169  aRendered.setHeight(rS.GetHeight());
4170 
4171  ww8::Frame* pFrame = nullptr;
4172  for (auto& rFrame : m_rExport.m_aFrames)
4173  {
4174  if (pFlyFrameFormat == &rFrame.GetFrameFormat())
4175  {
4176  pFrame = &rFrame;
4177  break;
4178  }
4179  }
4180 
4181  /*
4182  If the graphic is not of type WMF then we will have to store two
4183  graphics, one in the native format wrapped in shppict, and the other in
4184  the wmf format wrapped in nonshppict, so as to keep wordpad happy. If its
4185  a wmf already then we don't need any such wrapping
4186  */
4187  bool bIsWMF = pBLIPType && std::strcmp(pBLIPType, OOO_STRING_SVTOOLS_RTF_WMETAFILE) == 0;
4188  const SwAttrSet* pAttrSet = pGrfNode->GetpSwAttrSet();
4189  if (!pFrame || pFrame->IsInline())
4190  {
4191  if (!bIsWMF)
4194  }
4195  else
4196  {
4200  m_pFlyFrameSize = &aRendered;
4201  m_rExport.m_pParentFrame = pFrame;
4203  m_rExport.SetRTFFlySyntax(true);
4204  m_rExport.OutputFormat(pFrame->GetFrameFormat(), false, false, true);
4206  m_rExport.SetRTFFlySyntax(false);
4207  m_rExport.m_pParentFrame = nullptr;
4208  m_pFlyFrameSize = nullptr;
4209 
4210  std::vector<std::pair<OString, OString>> aFlyProperties;
4211  aFlyProperties.push_back(std::make_pair<OString, OString>(
4212  "shapeType", OString::number(ESCHER_ShpInst_PictureFrame)));
4213  aFlyProperties.push_back(std::make_pair<OString, OString>(
4214  "wzDescription", msfilter::rtfutil::OutString(pFlyFrameFormat->GetObjDescription(),
4216  aFlyProperties.push_back(std::make_pair<OString, OString>(
4217  "wzName", msfilter::rtfutil::OutString(pFlyFrameFormat->GetObjTitle(),
4219 
4220  // If we have a wrap polygon, then handle that here.
4221  if (pFlyFrameFormat->GetSurround().IsContour())
4222  {
4223  if (const SwNoTextNode* pNd
4224  = sw::util::GetNoTextNodeFromSwFrameFormat(*pFlyFrameFormat))
4225  {
4226  const tools::PolyPolygon* pPolyPoly = pNd->HasContour();
4227  if (pPolyPoly && pPolyPoly->Count())
4228  {
4229  tools::Polygon aPoly
4230  = sw::util::CorrectWordWrapPolygonForExport(*pPolyPoly, pNd);
4231  OStringBuffer aVerticies;
4232  for (sal_uInt16 i = 0; i < aPoly.GetSize(); ++i)
4233  aVerticies.append(";(")
4234  .append(aPoly[i].X())
4235  .append(",")
4236  .append(aPoly[i].Y())
4237  .append(")");
4238  aFlyProperties.push_back(std::make_pair<OString, OString>(
4239  "pWrapPolygonVertices",
4240  "8;" + OString::number(aPoly.GetSize()) + aVerticies.makeStringAndClear()));
4241  }
4242  }
4243  }
4244 
4245  // Below text, behind document, opaque: they all refer to the same thing.
4246  if (!pFlyFrameFormat->GetOpaque().GetValue())
4247  aFlyProperties.push_back(std::make_pair<OString, OString>("fBehindDocument", "1"));
4248 
4249  if (pAttrSet)
4250  {
4251  if (sal_Int32 nRot = pAttrSet->Get(RES_GRFATR_ROTATION).GetValue())
4252  {
4253  // See writerfilter::rtftok::RTFSdrImport::applyProperty(),
4254  // positive rotation angles are clockwise in RTF, we have them
4255  // as counter-clockwise.
4256  // Additionally, RTF type is 0..360*2^16, our is 0..360*10.
4257  nRot = nRot * -1 * RTF_MULTIPLIER / 10;
4258  aFlyProperties.emplace_back("rotation", OString::number(nRot));
4259  }
4260  }
4261 
4262  for (const std::pair<OString, OString>& rPair : aFlyProperties)
4263  {
4266  m_rExport.Strm().WriteOString(rPair.first);
4268  m_rExport.Strm().WriteOString(rPair.second);
4269  m_rExport.Strm().WriteCharPtr("}}");
4270  }
4272  " pib"
4273  "}{" OOO_STRING_SVTOOLS_RTF_SV " ");
4274  }
4275 
4276  bool bWritePicProp = !pFrame || pFrame->IsInline();
4277  if (pBLIPType)
4278  ExportPICT(pFlyFrameFormat, aSize, aRendered, aMapped, rCr, pBLIPType, pGraphicAry, nSize,
4279  m_rExport, &m_rExport.Strm(), bWritePicProp, pAttrSet);
4280  else
4281  {
4282  aStream.Seek(0);
4283  if (GraphicConverter::Export(aStream, rGraphic, aConvertDestinationFormat) != ERRCODE_NONE)
4284  SAL_WARN("sw.rtf", "failed to export the graphic");
4285  pBLIPType = pConvertDestinationBLIPType;
4286  nSize = aStream.TellEnd();
4287  pGraphicAry = static_cast<sal_uInt8 const*>(aStream.GetData());
4288 
4289  ExportPICT(pFlyFrameFormat, aSize, aRendered, aMapped, rCr, pBLIPType, pGraphicAry, nSize,
4290  m_rExport, &m_rExport.Strm(), bWritePicProp, pAttrSet);
4291  }
4292 
4293  if (!pFrame || pFrame->IsInline())
4294  {
4295  if (!bIsWMF)
4296  {
4299 
4300  aStream.Seek(0);
4301  if (GraphicConverter::Export(aStream, rGraphic, ConvertDataFormat::WMF) != ERRCODE_NONE)
4302  SAL_WARN("sw.rtf", "failed to export the graphic");
4304  nSize = aStream.TellEnd();
4305  pGraphicAry = static_cast<sal_uInt8 const*>(aStream.GetData());
4306 
4307  ExportPICT(pFlyFrameFormat, aSize, aRendered, aMapped, rCr, pBLIPType, pGraphicAry,
4308  nSize, m_rExport, &m_rExport.Strm());
4309 
4310  m_rExport.Strm().WriteChar('}');
4311  }
4312  }
4313  else
4314  m_rExport.Strm().WriteCharPtr("}}}}"); // Close SV, SP, SHPINST and SHP.
4315 
4317 }
4318 
4319 void RtfAttributeOutput::BulletDefinition(int /*nId*/, const Graphic& rGraphic, Size aSize)
4320 {
4323 
4325  m_rExport.OutULong(aSize.Width());
4327  m_rExport.OutULong(aSize.Height());
4328 
4330  const sal_uInt8* pGraphicAry = nullptr;
4331  SvMemoryStream aStream;
4332  if (GraphicConverter::Export(aStream, rGraphic, ConvertDataFormat::PNG) != ERRCODE_NONE)
4333  SAL_WARN("sw.rtf", "failed to export the numbering picture bullet");
4334  sal_uInt32 nSize = aStream.TellEnd();
4335  pGraphicAry = static_cast<sal_uInt8 const*>(aStream.GetData());
4336  msfilter::rtfutil::WriteHex(pGraphicAry, nSize, &m_rExport.Strm());
4337  m_rExport.Strm().WriteCharPtr("}}"); // pict, shppict
4338 }
4339 
4340 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
#define OOO_STRING_SVTOOLS_RTF_SNEXT
#define OOO_STRING_SVTOOLS_RTF_ULW
sal_uInt16 Count() const
long GetLeft() const
void FormatBackground(const SvxBrushItem &rBrush) override
Sfx item RES_BACKGROUND.
constexpr TypedWhichId< SwCropGrf > RES_GRFATR_CROPGRF(132)
void FormatTextGrid(const SwTextGridItem &rItem) override
Sfx item RES_TEXTGRID.
bool GetValue() const
SvxNumType GetNumberingType() const
long Width() const
bool IsContour() const
Definition: fmtsrnd.hxx:53
SvStream & OutULong(sal_uLong nVal)
Definition: rtfexport.cxx:1076
void CharFontCTL(const SvxFontItem &rFont) override
Sfx item RES_CHRATR_CTL_FONT.
#define OOO_STRING_SVTOOLS_RTF_QL
void StartRun(const SwRedlineData *pRedlineData, sal_Int32 nPos, bool bSingleEmptyRun=false) override
Start of the text run.
Wrapper around OStringBuffers, so less hexdump of graphics have to be kept in memory during RTF expor...
bool EndURL(bool isAtEndOfParagraph) override
Output URL end.
void TableHeight(ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner) override
#define OOO_STRING_SVTOOLS_RTF_CONTEXTUALSPACE
#define OOO_STRING_SVTOOLS_RTF_LTRSECT
#define OOO_STRING_SVTOOLS_RTF_ACCCOMMA
SVX_NUM_CHARS_UPPER_LETTER_N
void CharGrabBag(const SfxGrabBagItem &rItem) override
Sfx item RES_CHRATR_GRABBAG.
void Redline(const SwRedlineData *pRedline) override
Output redlining.
SwNoTextNode * GetNoTextNodeFromSwFrameFormat(const SwFrameFormat &rFormat)
Get the SwNoTextNode associated with a SwFrameFormat if here is one.
sal_Int64 GetAspect() const
Definition: ndole.hxx:136
void TableSpacing(ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner) override
#define OOO_STRING_SVTOOLS_RTF_WIDCTLPAR
sal_Int32 nIndex
#define OOO_STRING_SVTOOLS_RTF_SHPRIGHT
void TextINetFormat(const SwFormatINetFormat &rURL) override
Sfx item RES_TXTATR_INETFMT.
SwCharFormat * GetCharFormat()
Definition: txtatr2.cxx:110
void FormatULSpace(const SvxULSpaceItem &rULSpace) override
Sfx item RES_UL_SPACE.
void FormatColumns_Impl(sal_uInt16 nCols, const SwFormatCol &rCol, bool bEven, SwTwips nPageSize) override
Sfx item RES_COL.
#define OOO_STRING_SVTOOLS_RTF_QR
#define OOO_STRING_SVTOOLS_RTF_ANIMTEXT
#define OOO_STRING_SVTOOLS_RTF_ULTHDASHD
sal_uInt16 GetRowSpan() const
Definition: wrtswtbl.hxx:77
#define OOO_STRING_SVTOOLS_RTF_ALANG
#define OOO_STRING_SVTOOLS_RTF_BRDRINSET
#define OOO_STRING_SVTOOLS_RTF_COLNO
sal_uInt16 Count() const
sal_Int32 GetLeft() const
std::vector< SwColumn > SwColumns
Definition: fmtclds.hxx:57
void FormatKeep(const SvxFormatKeepItem &rItem) override
Sfx item RES_KEEP.
#define OOO_STRING_SVTOOLS_RTF_FSWISS
constexpr TypedWhichId< SvxFontItem > RES_CHRATR_CTL_FONT(27)
FAMILY_SCRIPT
void EndRuby(const SwTextNode &rNode, sal_Int32 nPos) override
Output ruby end.
#define OOO_STRING_SVTOOLS_RTF_SN
void FieldVanish(const OUString &rText, ww::eField eType) override
OUString GetObjDescription() const
Definition: atrfrm.cxx:3158
void CharKerning(const SvxKerningItem &rKerning) override
Sfx item RES_CHRATR_KERNING.
#define OOO_STRING_SVTOOLS_RTF_ULHWAVE
sal_uInt16 GetLower() const
SvxAdjust GetAdjust() const
#define OOO_STRING_SVTOOLS_RTF_PNGBLIP
SwOLENode * GetOLENode()
Inline methods from Node.hxx.
Definition: ndole.hxx:161
void ParaSnapToGrid(const SvxParaGridItem &rItem) override
Sfx item RES_PARATR_SNAPTOGRID.
#define OOO_STRING_SVTOOLS_RTF_CLVMGF
void CharBidiRTL(const SfxPoolItem &rItem) override
Sfx item RES_CHRATR_BidiRTL.
void WriteBookmarks_Impl(std::vector< OUString > &rStarts, std::vector< OUString > &rEnds)
bool GetValue() const
const SwOLEObj & GetOLEObj() const
Definition: ndole.hxx:112
double ConvertBorderWidthToWord(SvxBorderLineStyle, double)
void EndRun(const SwTextNode *pNode, sal_Int32 nPos, bool bLastRun=false) override
End of the text run.
#define OOO_STRING_SVTOOLS_RTF_SUB
void StartTableRow(const ww8::WW8TableNodeInfoInner::Pointer_t &pTableTextNodeInfoInner)
FAMILY_MODERN
#define OOO_STRING_SVTOOLS_RTF_EXPNDTW
RtfAttributeOutput(RtfExport &rExport)
#define OOO_STRING_SVTOOLS_RTF_FTNALT
#define OOO_STRING_SVTOOLS_RTF_BRDRENGRAVE
SVX_NUM_FULL_WIDTH_ARABIC
sal_Unicode GetStartBracket() const
std::string GetValue
#define OOO_STRING_SVTOOLS_RTF_FMODERN
rtl_TextEncoding GetCurrentEncoding() const
Definition: rtfexport.hxx:177
void CharBackground(const SvxBrushItem &rBrush) override
Sfx item RES_CHRATR_BACKGROUND.
#define OOO_STRING_SVTOOLS_RTF_SBASEDON
void FormatVertOrientation(const SwFormatVertOrient &rFlyVert) override
Sfx item RES_VERT_ORIENT.
#define OOO_STRING_SVTOOLS_RTF_ULDASH
sal_uInt16 GetCountBy() const
Definition: lineinfo.hxx:74
long Height() const
#define OOO_STRING_SVTOOLS_RTF_S
void PostitField(const SwField *pField) override
#define OOO_STRING_SVTOOLS_RTF_CLBRDRR
const SwNumFormat * GetNumFormat(sal_uInt16 i) const
Definition: number.cxx:88
#define OOO_STRING_SVTOOLS_RTF_SLMULT
#define OOO_STRING_SVTOOLS_RTF_LI
#define OOO_STRING_SVTOOLS_RTF_PICCROPT
#define OOO_STRING_SVTOOLS_RTF_LEVELFOLLOW
long GetWidth() const
std::size_t GetAuthor() const
Definition: redline.hxx:127
#define OOO_STRING_SVTOOLS_RTF_FOOTNOTE
#define OOO_STRING_SVTOOLS_RTF_FROMAN
#define OOO_STRING_SVTOOLS_RTF_FFTYPE
LINESTYLE_BOLD
#define OOO_STRING_SVTOOLS_RTF_TLUL
#define OOO_STRING_SVTOOLS_RTF_FOOTERY
SVX_NUM_NUMBER_NONE
sal_uInt16 GetPageNum() const
Definition: fmtanchr.hxx:66
#define OOO_STRING_SVTOOLS_RTF_FFOWNSTAT
#define OOO_STRING_SVTOOLS_RTF_TQDEC
sal_uInt8 GetTransparency() const
sal_uInt8 TransColToIco(const Color &rCol)
#define OOO_STRING_SVTOOLS_RTF_ULDASHD
SwTwips GetPos() const
Definition: fmtornt.hxx:92
sal_uIntPtr sal_uLong
void SectionPageNumbering(sal_uInt16 nNumType, const ::std::optional< sal_uInt16 > &oPageRestartNumber) override
The style of the page numbers.
constexpr TypedWhichId< SvxLanguageItem > RES_CHRATR_LANGUAGE(10)
void CharHighlight(const SvxBrushItem &rBrush) override
Sfx item RES_CHRATR_HIGHLIGHT.
void FormatDrop(const SwTextNode &rNode, const SwFormatDrop &rSwFormatDrop, sal_uInt16 nStyle, ww8::WW8TableNodeInfo::Pointer_t pTextNodeInfo, ww8::WW8TableNodeInfoInner::Pointer_t pTextNodeInfoInner) override
#define OOO_STRING_SVTOOLS_RTF_CLPADFR
sal_uInt8 & GetProportionalHeight()
#define OOO_STRING_SVTOOLS_RTF_TRPADDB
#define OOO_STRING_SVTOOLS_RTF_ASPALPHA
#define OOO_STRING_SVTOOLS_RTF_NESTTABLEPROPRS
constexpr TypedWhichId< SvxFontHeightItem > RES_CHRATR_FONTSIZE(8)
bool FlyFrameOLEMath(const SwFlyFrameFormat *pFlyFrameFormat, SwOLENode &rOLENode, const Size &rSize)
Math export.
FontEmphasisMark
#define OOO_STRING_SVTOOLS_RTF_ULTHLDASH
#define OOO_STRING_SVTOOLS_RTF_UP
Base class of all fields.
Definition: fldbas.hxx:293
constexpr TypedWhichId< SwRotationGrf > RES_GRFATR_ROTATION(133)
const SwPageDesc * FindPageDesc(size_t *pPgDescNdIdx=nullptr) const
Search PageDesc with which this node is formatted.
Definition: node.cxx:465
#define OOO_STRING_SVTOOLS_RTF_PICCROPL
#define OOO_STRING_SVTOOLS_RTF_RIN
void ParaHangingPunctuation(const SfxBoolItem &rItem) override
Sfx item RES_PARATR_HANGINGPUNCTUATION.
SVX_NUM_CHARS_UPPER_LETTER
#define LO_STRING_SVTOOLS_RTF_LEVELPICTURE
css::uno::Reference< css::embed::XEmbeddedObject > const & GetOleRef()
Definition: ndole.cxx:912
#define OOO_STRING_SVTOOLS_RTF_FORMFIELD
SvStream & Strm()
Definition: rtfexport.cxx:1054
sal_Int64 n
GraphicType
#define OOO_STRING_SVTOOLS_RTF_AF
#define OOO_STRING_SVTOOLS_RTF_FFNAME
#define OOO_STRING_SVTOOLS_RTF_LISTLEVEL
void ParaNumRule_Impl(const SwTextNode *pTextNd, sal_Int32 nLvl, sal_Int32 nNumId) override
Sfx item RES_PARATR_NUMRULE.
#define OOO_STRING_SVTOOLS_RTF_ATNREF
#define OOO_STRING_SVTOOLS_RTF_SHPBXCOLUMN
SVX_NUM_CIRCLE_NUMBER
#define OOO_STRING_SVTOOLS_RTF_SL
void ParaSplit(const SvxFormatSplitItem &rSplit) override
Sfx item RES_PARATR_SPLIT.
void StartFont(const OUString &rFamilyName) const
Start the font.
aBuf
void CharFontCJK(const SvxFontItem &rFont) override
Sfx item RES_CHRATR_CJK_FONT.
LINESTYLE_BOLDWAVE
sal_Int16 nId
sal_uInt16 GetDistance(SvxBoxItemLine nLine) const
void FlyFrameGraphic(const SwFlyFrameFormat *pFlyFrameFormat, const SwGrfNode *pGrfNode)
Output graphic fly frames.
#define OOO_STRING_SVTOOLS_RTF_PICT
void clear()
Similar to ->setLength(0), but for all buffers.
void TableInfoCell(ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner) override
virtual OUString GetPar1() const override
Author.
Definition: docufld.cxx:1799
sal_uInt64 Seek(sal_uInt64 nPos)
void ParaWidows(const SvxWidowsItem &rWidows) override
Sfx item RES_PARATR_WIDOWS.
#define cDfltFillChar
#define OOO_STRING_SVTOOLS_RTF_FIELD
SwTableLine is one table row in the document model.
Definition: swtable.hxx:344
#define OOO_STRING_SVTOOLS_RTF_KEEPN
#define OOO_STRING_SVTOOLS_RTF_ULDB
#define OOO_STRING_SVTOOLS_RTF_SAUTOUPD
#define OOO_STRING_SVTOOLS_RTF_SHPWRK
void FormatSurround(const SwFormatSurround &rSurround) override
Sfx item RES_SURROUND.
void SetTextLeft(const long nL, const sal_uInt16 nProp=100)
SwNode & GetNode() const
Definition: ndindex.hxx:119
#define OOO_STRING_SVTOOLS_RTF_PICSCALEY
MirrorGraph
Definition: grfatr.hxx:31
long SwTwips
Definition: swtypes.hxx:49
void EndStyles(sal_uInt16 nNumberOfStyles) override
End of the styles table.
#define LO_STRING_SVTOOLS_RTF_MMATH
#define LO_STRING_SVTOOLS_RTF_MMATHPICT
void RefField(const SwField &rField, const OUString &rRef) override
#define OOO_STRING_SVTOOLS_RTF_INTBL
SvxFrameDirection
#define OOO_STRING_SVTOOLS_RTF_CLTXTBRL
#define OOO_STRING_SVTOOLS_RTF_SOUTLVL
#define OOO_STRING_SVTOOLS_RTF_BKMKEND
void CharLanguage(const SvxLanguageItem &rLanguage) override
Sfx item RES_CHRATR_LANGUAGE.
#define OOO_STRING_SVTOOLS_RTF_OUTLINELEVEL
#define OOO_STRING_SVTOOLS_RTF_FLYANCHOR
#define OOO_STRING_SVTOOLS_RTF_FSCRIPT
void StartAbstractNumbering(sal_uInt16 nId) override
Start of the abstract numbering definition instance.
#define OOO_STRING_SVTOOLS_RTF_CLVMRG
SvStream & WriteOString(const OString &rStr)
#define OOO_STRING_SVTOOLS_RTF_RTLPAR
bool IsEndNote() const
Definition: fmtftn.hxx:74
#define DFLT_ESC_AUTO_SUB
#define OOO_STRING_SVTOOLS_RTF_LEVELSTARTAT
#define OOO_STRING_SVTOOLS_RTF_FLDRSLT
void StartStyles() override
Start of the styles table.
void FormatFrameSize(const SwFormatFrameSize &rSize) override
Sfx item RES_FRM_SIZE.
FAMILY_ROMAN
void SectionTitlePage() override
Has different headers/footers for the title page.
tools::Polygon CorrectWordWrapPolygonForExport(const tools::PolyPolygon &rPolyPoly, const SwNoTextNode *pNd)
Undo all scaling / move tricks of the wrap polygon done during import.
void CharPostureCTL(const SvxPostureItem &rPosture) override
Sfx item RES_CHRATR_CTL_POSTURE.
void SectFootnoteEndnotePr() override
for footnote/endnote section properties
#define OOO_STRING_SVTOOLS_RTF_ACCUNDERDOT
#define OOO_STRING_SVTOOLS_RTF_SFTNNALC
void FlyFrameOLE(const SwFlyFrameFormat *pFlyFrameFormat, SwOLENode &rOLENode, const Size &rSize)
#define OOO_STRING_SVTOOLS_RTF_LTRCH
const sal_uInt8 ColumnBreak
void SectionBiDi(bool bBiDi) override
Columns populated from right/numbers on the right side?
const editeng::SvxBorderLine * GetRight() const
bool m_bSingleEmptyRun
If we're in a paragraph that has a single empty run only.
#define OOO_STRING_SVTOOLS_RTF_SBKNONE
void CharCaseMap(const SvxCaseMapItem &rCaseMap) override
Sfx item Sfx item RES_CHRATR_CASEMAP.
sal_Int16 GetRelationOrient() const
Definition: fmtornt.hxx:55
#define OOO_STRING_SVTOOLS_RTF_CLVERTALB
#define OOO_STRING_SVTOOLS_RTF_PICH
rtl_TextEncoding GetDefaultEncoding() const
Definition: rtfexport.hxx:172
#define OOO_STRING_SVTOOLS_RTF_MARGRSXN
EmbeddedObjectRef * pObject
#define OOO_STRING_SVTOOLS_RTF_RTLROW
static OString OutTBLBorderLine(RtfExport const &rExport, const editeng::SvxBorderLine *pLine, const char *pStr)
OUString FieldString(ww::eField eIndex)
Definition: ww8atr.cxx:2616
SvStream & WriteCharPtr(const char *pBuf)
#define OOO_STRING_SVTOOLS_RTF_HIGHLIGHT
#define OOO_STRING_SVTOOLS_RTF_SHPPICT
#define OOO_STRING_SVTOOLS_RTF_FAROMAN
int GetActualListLevel() const
Returns the actual list level of this text node, when it is a list item.
Definition: ndtxt.cxx:4089
SwTableFormat * GetFrameFormat()
Definition: swtable.hxx:201
void StartSection() override
Start of the section properties.
void TableBidi(ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner) override
SVX_NUM_ARABIC_ZERO
void CharWeight(const SvxWeightItem &rWeight) override
Sfx item RES_CHRATR_WEIGHT.
Value in Var-direction gives minimum (can be exceeded but not be less).
static bool bFootnote
Definition: insfnote.cxx:33
void TableBackgrounds(ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner) override
size_type size() const
Definition: swtable.hxx:74
FontItalic GetPosture() const
#define OOO_STRING_SVTOOLS_RTF_LINECONT
#define OOO_STRING_SVTOOLS_RTF_CLPADFB
#define OOO_STRING_SVTOOLS_RTF_CHBRDR
RtfStringBuffer m_RunText
static bool isTextBox(const SwFrameFormat &rFrameFormat)
Is this a standalone TextFrame, or used as a TextBox of a shape?
const SvxBoxItem & GetBox(bool=true) const
Definition: frmatr.hxx:84
virtual sal_uInt64 TellEnd() override
const SwTextINetFormat * GetTextINetFormat() const
Definition: fmtinfmt.hxx:70
#define OOO_STRING_SVTOOLS_RTF_FLYPAGE
LINESTYLE_DASH
void NumberingDefinition(sal_uInt16 nId, const SwNumRule &rRule) override
Definition of a numbering instance.
#define OOO_STRING_SVTOOLS_RTF_CLPADFL
WEIGHT_BOLD
#define OOO_STRING_SVTOOLS_RTF_FAHANG
const Color & GetStartColor() const
#define OOO_STRING_SVTOOLS_RTF_HICH