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