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