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