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 (SvxBorderLineWidth::Hairline == 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  // Do not call MoveCharacterProperties(),
388  // Otherwise associate properties in the paragraph style are ruined.
389  const OString aProperties = m_aStyles.makeStringAndClear();
390  m_rExport.Strm().WriteOString(aProperties);
391 }
392 
393 void RtfAttributeOutput::StartRun(const SwRedlineData* pRedlineData, sal_Int32 /*nPos*/,
394  bool bSingleEmptyRun)
395 {
396  SAL_INFO("sw.rtf", __func__ << ", bSingleEmptyRun: " << bSingleEmptyRun);
397 
398  m_bInRun = true;
399  m_bSingleEmptyRun = bSingleEmptyRun;
400  if (!m_bSingleEmptyRun)
401  m_aRun->append('{');
402 
403  // if there is some redlining in the document, output it
404  Redline(pRedlineData);
405 
406  OSL_ENSURE(m_aRunText.getLength() == 0, "m_aRunText is not empty");
407 }
408 
409 void RtfAttributeOutput::EndRun(const SwTextNode* /*pNode*/, sal_Int32 /*nPos*/, bool /*bLastRun*/)
410 {
411  m_aRun->append(SAL_NEWLINE_STRING);
412  m_aRun.appendAndClear(m_aRunText);
413 
414  if (m_bInRuby)
415  {
416  m_aRun->append(")}}{" OOO_STRING_SVTOOLS_RTF_FLDRSLT " {}}}");
417  m_bInRuby = false;
418  }
419 
420  if (!m_bSingleEmptyRun && m_bInRun)
421  m_aRun->append('}');
422  m_bInRun = false;
423 }
424 
426 {
427  OSL_ENSURE(m_aStyles.getLength() == 0, "m_aStyles is not empty");
428 }
429 
431 {
432  const OString aProperties = MoveCharacterProperties(true);
433  m_aRun->append(aProperties);
434 }
435 
436 OString RtfAttributeOutput::MoveCharacterProperties(bool aAutoWriteRtlLtr)
437 {
438  const OString aAssocHich = m_aStylesAssocHich.makeStringAndClear();
439  const OString aAssocDbch = m_aStylesAssocDbch.makeStringAndClear();
440  const OString aAssocRtlch = m_aStylesAssocRtlch.makeStringAndClear();
441  const OString aAssocLtrch = m_aStylesAssocLtrch.makeStringAndClear();
442  const OString aNormal = m_aStyles.makeStringAndClear();
443  OStringBuffer aBuf;
444 
445  if (aAutoWriteRtlLtr && !m_bControlLtrRtl)
446  {
447  m_bControlLtrRtl = !aAssocRtlch.isEmpty();
448  m_bIsRTL = false;
449  m_nScript = i18n::ScriptType::LATIN;
450  }
451 
452  if (m_bIsRTL)
453  {
454  if (!aAssocRtlch.isEmpty())
455  {
456  aBuf.append(OOO_STRING_SVTOOLS_RTF_LTRCH + aAssocLtrch
457  + " " OOO_STRING_SVTOOLS_RTF_RTLCH + aAssocRtlch);
458  }
459  }
460  else
461  {
462  if (!aAssocRtlch.isEmpty())
463  {
464  aBuf.append(OOO_STRING_SVTOOLS_RTF_RTLCH + aAssocRtlch
465  + " " OOO_STRING_SVTOOLS_RTF_LTRCH + aAssocLtrch);
466  }
467  if (!aAssocHich.isEmpty())
468  {
469  aBuf.append(OOO_STRING_SVTOOLS_RTF_HICH + aAssocHich);
470  }
471  if (!aNormal.isEmpty())
472  {
473  aBuf.append(OOO_STRING_SVTOOLS_RTF_LOCH + aNormal);
474  }
475  if (!aAssocDbch.isEmpty())
476  {
477  aBuf.append(OOO_STRING_SVTOOLS_RTF_DBCH + aAssocDbch);
478  }
479  }
480 
481  if (m_bControlLtrRtl)
482  {
483  m_bControlLtrRtl = false;
484 
485  switch (m_nScript)
486  {
487  case i18n::ScriptType::LATIN:
488  aBuf.append(OOO_STRING_SVTOOLS_RTF_LOCH);
489  break;
490  case i18n::ScriptType::ASIAN:
491  aBuf.append(OOO_STRING_SVTOOLS_RTF_DBCH);
492  break;
493  case i18n::ScriptType::COMPLEX:
494  /* noop */
495  default:
496  /* should not happen? */
497  break;
498  }
499  }
500 
501  return aBuf.makeStringAndClear();
502 }
503 
504 void RtfAttributeOutput::RunText(const OUString& rText, rtl_TextEncoding /*eCharSet*/)
505 {
506  SAL_INFO("sw.rtf", __func__ << ", rText: " << rText);
507  RawText(rText, m_rExport.GetCurrentEncoding());
508 }
509 
510 OStringBuffer& RtfAttributeOutput::RunText() { return m_aRunText.getLastBuffer(); }
511 
512 void RtfAttributeOutput::RawText(const OUString& rText, rtl_TextEncoding eCharSet)
513 {
514  m_aRunText->append(msfilter::rtfutil::OutString(rText, eCharSet));
515 }
516 
517 void RtfAttributeOutput::StartRuby(const SwTextNode& rNode, sal_Int32 /*nPos*/,
518  const SwFormatRuby& rRuby)
519 {
520  WW8Ruby aWW8Ruby(rNode, rRuby, GetExport());
521  OUString aStr(FieldString(ww::eEQ) + "\\* jc");
522  aStr += OUString::number(aWW8Ruby.GetJC()) + " \\* \"Font:" + aWW8Ruby.GetFontFamily()
523  + "\" \\* hps";
524  aStr += OUString::number((aWW8Ruby.GetRubyHeight() + 5) / 10) + " \\o";
525  if (aWW8Ruby.GetDirective())
526  {
527  aStr += "\\a" + OUStringChar(aWW8Ruby.GetDirective());
528  }
529  aStr += "(\\s\\up " + OUString::number((aWW8Ruby.GetBaseHeight() + 10) / 20 - 1) + "(";
530  m_rExport.OutputField(nullptr, ww::eEQ, aStr, FieldFlags::Start | FieldFlags::CmdStart);
531  aStr = rRuby.GetText() + "),";
532  m_rExport.OutputField(nullptr, ww::eEQ, aStr, FieldFlags::NONE);
533  m_bInRuby = true;
534 }
535 
536 void RtfAttributeOutput::EndRuby(const SwTextNode& /*rNode*/, sal_Int32 /*nPos*/) {}
537 
538 bool RtfAttributeOutput::StartURL(const OUString& rUrl, const OUString& rTarget)
539 {
540  m_aURLs.push(rUrl);
541  // Ignore hyperlink without a URL.
542  if (!rUrl.isEmpty())
543  {
544  m_aRun->append('{');
545  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FIELD);
546  m_aRun->append('{');
547  m_aRun->append(OOO_STRING_SVTOOLS_RTF_IGNORE);
548  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FLDINST);
549  m_aRun->append(" HYPERLINK ");
550 
551  m_aRun->append("\"");
552  m_aRun->append(msfilter::rtfutil::OutString(rUrl, m_rExport.GetCurrentEncoding()));
553  m_aRun->append("\" ");
554 
555  if (!rTarget.isEmpty())
556  {
557  m_aRun->append("\\\\t \"");
558  m_aRun->append(msfilter::rtfutil::OutString(rTarget, m_rExport.GetCurrentEncoding()));
559  m_aRun->append("\" ");
560  }
561 
562  m_aRun->append("}");
563  m_aRun->append("{" OOO_STRING_SVTOOLS_RTF_FLDRSLT " {");
564  }
565  return true;
566 }
567 
568 bool RtfAttributeOutput::EndURL(bool const isAtEndOfParagraph)
569 {
570  if (m_aURLs.empty())
571  {
572  return true;
573  }
574 
575  const OUString& rURL = m_aURLs.top();
576  if (!rURL.isEmpty())
577  {
578  // UGLY: usually EndRun is called earlier, but there is an extra
579  // call to OutAttrWithRange() when at the end of the paragraph,
580  // so in that special case the output needs to be appended to the
581  // new run's text instead of the previous run
582  if (isAtEndOfParagraph)
583  {
584  // close the fldrslt group
585  m_aRunText->append("}}");
586  // close the field group
587  m_aRunText->append('}');
588  }
589  else
590  {
591  // close the fldrslt group
592  m_aRun->append("}}");
593  // close the field group
594  m_aRun->append('}');
595  }
596  }
597  m_aURLs.pop();
598  return true;
599 }
600 
601 void RtfAttributeOutput::FieldVanish(const OUString& /*rText*/, ww::eField /*eType*/,
602  OUString const* /*pBookmarkName*/)
603 {
604  SAL_INFO("sw.rtf", "TODO: " << __func__);
605 }
606 
608 {
609  if (!pRedline)
610  return;
611 
612  if (pRedline->GetType() == RedlineType::Insert)
613  {
614  m_aRun->append(OOO_STRING_SVTOOLS_RTF_REVISED);
615  m_aRun->append(OOO_STRING_SVTOOLS_RTF_REVAUTH);
616  m_aRun->append(static_cast<sal_Int32>(
617  m_rExport.GetRedline(SW_MOD()->GetRedlineAuthor(pRedline->GetAuthor()))));
618  m_aRun->append(OOO_STRING_SVTOOLS_RTF_REVDTTM);
619  }
620  else if (pRedline->GetType() == RedlineType::Delete)
621  {
622  m_aRun->append(OOO_STRING_SVTOOLS_RTF_DELETED);
623  m_aRun->append(OOO_STRING_SVTOOLS_RTF_REVAUTHDEL);
624  m_aRun->append(static_cast<sal_Int32>(
625  m_rExport.GetRedline(SW_MOD()->GetRedlineAuthor(pRedline->GetAuthor()))));
626  m_aRun->append(OOO_STRING_SVTOOLS_RTF_REVDTTMDEL);
627  }
628  m_aRun->append(static_cast<sal_Int32>(sw::ms::DateTime2DTTM(pRedline->GetTimeStamp())));
629  m_aRun->append(' ');
630 }
631 
633  const SwFormatDrop& /*rSwFormatDrop*/, sal_uInt16 /*nStyle*/,
634  ww8::WW8TableNodeInfo::Pointer_t /*pTextNodeInfo*/,
635  ww8::WW8TableNodeInfoInner::Pointer_t /*pTextNodeInfoInner*/)
636 {
637  SAL_INFO("sw.rtf", "TODO: " << __func__);
638 }
639 
640 void RtfAttributeOutput::ParagraphStyle(sal_uInt16 nStyle)
641 {
642  OString* pStyle = m_rExport.GetStyle(nStyle);
643  OStringBuffer aStyle;
644  aStyle.append(OOO_STRING_SVTOOLS_RTF_S);
645  aStyle.append(static_cast<sal_Int32>(nStyle));
646  if (pStyle)
647  aStyle.append(*pStyle);
648  if (!m_bBufferSectionHeaders)
649  m_rExport.Strm().WriteOString(aStyle);
650  else
651  m_aSectionHeaders.append(aStyle);
652 }
653 
655  ww8::WW8TableNodeInfoInner::Pointer_t /*pTableTextNodeInfoInner*/)
656 {
657  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_INTBL);
658  if (m_nTableDepth > 1)
659  {
660  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ITAP);
661  m_aStyles.append(static_cast<sal_Int32>(m_nTableDepth));
662  }
663  m_bWroteCellInfo = true;
664 }
665 
667 {
668  /* noop */
669 }
670 
672  ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)
673 {
674  InitTableHelper(pTableTextNodeInfoInner);
675 
676  const SwTable* pTable = pTableTextNodeInfoInner->getTable();
677  SwFrameFormat* pFormat = pTable->GetFrameFormat();
678 
679  m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_TROWD);
680  TableOrientation(pTableTextNodeInfoInner);
681  TableBidi(pTableTextNodeInfoInner);
682  TableHeight(pTableTextNodeInfoInner);
683  TableCanSplit(pTableTextNodeInfoInner);
684 
685  // Cell margins
686  const SvxBoxItem& rBox = pFormat->GetBox();
687  static const SvxBoxItemLine aBorders[] = { SvxBoxItemLine::TOP, SvxBoxItemLine::LEFT,
688  SvxBoxItemLine::BOTTOM, SvxBoxItemLine::RIGHT };
689 
690  static const char* aRowPadNames[]
693 
694  static const char* aRowPadUnits[]
697 
698  for (int i = 0; i < 4; ++i)
699  {
700  m_aRowDefs.append(aRowPadUnits[i]);
701  m_aRowDefs.append(sal_Int32(3));
702  m_aRowDefs.append(aRowPadNames[i]);
703  m_aRowDefs.append(static_cast<sal_Int32>(rBox.GetDistance(aBorders[i])));
704  }
705 
706  // The cell-dependent properties
707  const double fWidthRatio = m_pTableWrt->GetAbsWidthRatio();
708  const SwWriteTableRows& aRows = m_pTableWrt->GetRows();
709  SwWriteTableRow* pRow = aRows[pTableTextNodeInfoInner->getRow()].get();
710  SwTwips nSz = 0;
711 
712  // Not using m_nTableDepth, which is not yet incremented here.
713  sal_uInt32 nCurrentDepth = pTableTextNodeInfoInner->getDepth();
714  m_aCells[nCurrentDepth] = pRow->GetCells().size();
715  for (sal_uInt32 i = 0; i < m_aCells[nCurrentDepth]; i++)
716  {
717  const SwWriteTableCell* const pCell = pRow->GetCells()[i].get();
718  const SwFrameFormat* pCellFormat = pCell->GetBox()->GetFrameFormat();
719 
720  pTableTextNodeInfoInner->setCell(i);
721  TableCellProperties(pTableTextNodeInfoInner);
722 
723  // Right boundary: this can't be in TableCellProperties as the old
724  // value of nSz is needed.
725  nSz += pCellFormat->GetFrameSize().GetWidth();
726  m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CELLX);
727  m_aRowDefs.append(static_cast<sal_Int32>(pFormat->GetLRSpace().GetLeft()
728  + rtl::math::round(nSz * fWidthRatio)));
729  }
730 }
731 
733  ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)
734 {
735  /*
736  * The function name is a bit misleading: given that we write borders
737  * before each row, we just have borders, not default ones. Additionally,
738  * this function actually writes borders for a specific cell only and is
739  * called for each cell.
740  */
741 
742  const SwWriteTableRows& aRows = m_pTableWrt->GetRows();
743  SwWriteTableRow* pRow = aRows[pTableTextNodeInfoInner->getRow()].get();
744  const SwWriteTableCell* const pCell
745  = pRow->GetCells()[pTableTextNodeInfoInner->getCell()].get();
746  const SwFrameFormat* pCellFormat = pCell->GetBox()->GetFrameFormat();
747  const SvxBoxItem* pItem = pCellFormat->GetAttrSet().GetItemIfSet(RES_BOX);
748  if (!pItem)
749  return;
750 
751  auto& rBox = *pItem;
752  static const SvxBoxItemLine aBorders[] = { SvxBoxItemLine::TOP, SvxBoxItemLine::LEFT,
753  SvxBoxItemLine::BOTTOM, SvxBoxItemLine::RIGHT };
754  static const char* aBorderNames[]
757  //Yes left and top are swapped with each other for cell padding! Because
758  //that's what the thundering annoying rtf export/import word xp does.
759  static const char* aCellPadNames[]
762  static const char* aCellPadUnits[]
765  for (int i = 0; i < 4; ++i)
766  {
767  if (const editeng::SvxBorderLine* pLn = rBox.GetLine(aBorders[i]))
768  m_aRowDefs.append(OutTBLBorderLine(m_rExport, pLn, aBorderNames[i]));
769  if (rBox.GetDistance(aBorders[i]))
770  {
771  m_aRowDefs.append(aCellPadUnits[i]);
772  m_aRowDefs.append(sal_Int32(3));
773  m_aRowDefs.append(aCellPadNames[i]);
774  m_aRowDefs.append(static_cast<sal_Int32>(rBox.GetDistance(aBorders[i])));
775  }
776  }
777 }
778 
780  ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)
781 {
782  const SwTable* pTable = pTableTextNodeInfoInner->getTable();
783  const SwTableBox* pTableBox = pTableTextNodeInfoInner->getTableBox();
784  const SwTableLine* pTableLine = pTableBox->GetUpper();
785 
786  Color aColor = COL_AUTO;
787  auto pTableColorProp
789  if (pTableColorProp)
790  aColor = pTableColorProp->GetColor();
791 
792  auto pRowColorProp
794  if (pRowColorProp && pRowColorProp->GetColor() != COL_AUTO)
795  aColor = pRowColorProp->GetColor();
796 
797  const SwWriteTableRows& aRows = m_pTableWrt->GetRows();
798  SwWriteTableRow* pRow = aRows[pTableTextNodeInfoInner->getRow()].get();
799  const SwWriteTableCell* const pCell
800  = pRow->GetCells()[pTableTextNodeInfoInner->getCell()].get();
801  const SwFrameFormat* pCellFormat = pCell->GetBox()->GetFrameFormat();
802  if (const SvxBrushItem* pBrushItem = pCellFormat->GetAttrSet().GetItemIfSet(RES_BACKGROUND))
803  {
804  if (pBrushItem->GetColor() != COL_AUTO)
805  aColor = pBrushItem->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  // vertical merges
896  if (pCell->GetRowSpan() > 1)
897  m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CLVMGF);
898  else if (pCell->GetRowSpan() == 0)
899  m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CLVMRG);
900 
901  // vertical alignment
902  const SwFormatVertOrient* pVertOrientItem
903  = pCellFormat->GetAttrSet().GetItemIfSet(RES_VERT_ORIENT);
904  if (!pVertOrientItem)
905  return;
906 
907  switch (pVertOrientItem->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 /*nLink*/, sal_uInt16 /*nWwId*/,
1152  sal_uInt16 nId, 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_aRunText->append(msfilter::rtfutil::OutString(rStart, m_rExport.GetCurrentEncoding()));
1729  m_aRunText->append('}');
1730  }
1731  rStarts.clear();
1732 
1733  for (const auto& rEnd : rEnds)
1734  {
1736  m_aRunText->append(msfilter::rtfutil::OutString(rEnd, m_rExport.GetCurrentEncoding()));
1737  m_aRunText->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(nId);
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(nId);
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  SwNodeOffset nStt = pNodeIndex ? pNodeIndex->GetIndex() + 1 : SwNodeOffset(0);
1939  SwNodeOffset nEnd
1940  = pNodeIndex ? pNodeIndex->GetNode().EndOfSectionIndex() : SwNodeOffset(0);
1941  m_rExport.SaveData(nStt, nEnd);
1942  m_rExport.m_pParentFrame = &rFrame;
1943  m_rExport.WriteText();
1944  m_rExport.RestoreData();
1945 
1946  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PARD);
1947  m_rExport.SetRTFFlySyntax(false);
1948  m_aRun->append(aSave);
1949  m_aRunText.clear();
1950  m_bInRun = bInRunOrig;
1951  m_bSingleEmptyRun = bSingleEmptyRunOrig;
1952 
1953  // Restore table state.
1954  m_rExport.m_pTableInfo = pTableInfoOrig;
1955  m_pTableWrt = std::move(pTableWrt);
1956  m_nTableDepth = nTableDepth;
1957  }
1958 
1959  m_rExport.m_pParentFrame = nullptr;
1960 
1961  m_rExport.Strm().WriteChar('}'); // shptxt
1962 
1963  if (bTextBox)
1964  {
1965  m_aRunText = aRunText;
1966  m_aRunText->append(m_rExport.getStream());
1967  m_rExport.resetStream();
1968  }
1969 }
1970 
1976 {
1977 private:
1981  bool const m_bSingleEmptyRun;
1982  bool const m_bInRun;
1983 
1984 public:
1986  : m_rRtf(rRtf)
1987  , m_Run(std::move(rRtf.m_aRun))
1988  , m_RunText(std::move(rRtf.m_aRunText))
1989  , m_bSingleEmptyRun(rRtf.m_bSingleEmptyRun)
1990  , m_bInRun(rRtf.m_bInRun)
1991  {
1992  m_rRtf.m_rExport.setStream();
1993  }
1995  {
1996  m_rRtf.m_aRun = std::move(m_Run);
1997  m_rRtf.m_aRunText = std::move(m_RunText);
1998  m_rRtf.m_bSingleEmptyRun = m_bSingleEmptyRun;
1999  m_rRtf.m_bInRun = m_bInRun;
2000 
2001  m_rRtf.m_aRunText->append(m_rRtf.m_rExport.getStream());
2002  m_rRtf.m_rExport.resetStream();
2003  }
2004 };
2005 
2006 void RtfAttributeOutput::OutputFlyFrame_Impl(const ww8::Frame& rFrame, const Point& /*rNdTopLeft*/)
2007 {
2008  const SwNode* pNode = rFrame.GetContent();
2009  const SwGrfNode* pGrfNode = pNode ? pNode->GetGrfNode() : nullptr;
2010 
2011  switch (rFrame.GetWriterType())
2012  {
2013  case ww8::Frame::eTextBox:
2014  {
2015  // If this is a TextBox of a shape, then ignore: it's handled in RtfSdrExport::StartShape().
2017  break;
2018 
2019  SaveRunState const saved(*this);
2020 
2021  m_rExport.m_pParentFrame = &rFrame;
2022 
2023  m_rExport.Strm().WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_SHP);
2024  m_rExport.Strm().WriteCharPtr(
2026 
2027  // Shape properties.
2028  m_aFlyProperties.push_back(std::make_pair<OString, OString>(
2029  "shapeType", OString::number(ESCHER_ShpInst_TextBox)));
2030 
2031  // When a frame has some low height, but automatically expanded due
2032  // to lots of contents, this size contains the real size.
2033  const Size aSize = rFrame.GetSize();
2034  m_pFlyFrameSize = &aSize;
2035 
2036  m_rExport.m_bOutFlyFrameAttrs = true;
2037  m_rExport.SetRTFFlySyntax(true);
2038  m_rExport.OutputFormat(rFrame.GetFrameFormat(), false, false, true);
2039 
2040  // Write ZOrder.
2041  if (const SdrObject* pObject = rFrame.GetFrameFormat().FindRealSdrObject())
2042  {
2043  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_SHPZ);
2044  m_rExport.OutULong(pObject->GetOrdNum());
2045  }
2046 
2047  m_rExport.Strm().WriteOString(m_aRunText.makeStringAndClear());
2048  m_rExport.Strm().WriteOString(m_aStyles.makeStringAndClear());
2049  m_rExport.m_bOutFlyFrameAttrs = false;
2050  m_rExport.SetRTFFlySyntax(false);
2051  m_pFlyFrameSize = nullptr;
2052 
2053  const SwFrameFormat& rFrameFormat = rFrame.GetFrameFormat();
2054  lcl_TextFrameShadow(m_aFlyProperties, rFrameFormat);
2055  lcl_TextFrameRelativeSize(m_aFlyProperties, rFrameFormat);
2056 
2057  for (const std::pair<OString, OString>& rPair : m_aFlyProperties)
2058  {
2059  m_rExport.Strm().WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_SP "{");
2060  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_SN " ");
2061  m_rExport.Strm().WriteOString(rPair.first);
2062  m_rExport.Strm().WriteCharPtr("}{" OOO_STRING_SVTOOLS_RTF_SV " ");
2063  m_rExport.Strm().WriteOString(rPair.second);
2064  m_rExport.Strm().WriteCharPtr("}}");
2065  }
2066  m_aFlyProperties.clear();
2067 
2068  writeTextFrame(rFrame);
2069 
2070  m_rExport.Strm().WriteChar('}'); // shpinst
2071  m_rExport.Strm().WriteChar('}'); // shp
2072 
2073  m_rExport.Strm().WriteCharPtr(SAL_NEWLINE_STRING);
2074  }
2075  break;
2076  case ww8::Frame::eGraphic:
2077  if (pGrfNode)
2078  {
2079  m_aRunText.append(dynamic_cast<const SwFlyFrameFormat*>(&rFrame.GetFrameFormat()),
2080  pGrfNode);
2081  }
2082  else if (!rFrame.IsInline())
2083  {
2084  m_rExport.m_pParentFrame = &rFrame;
2085  m_rExport.SetRTFFlySyntax(true);
2086  m_rExport.OutputFormat(rFrame.GetFrameFormat(), false, false, true);
2087  m_rExport.SetRTFFlySyntax(false);
2088  m_aRunText->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE);
2089  m_rExport.OutputFormat(rFrame.GetFrameFormat(), false, false, true);
2090  m_aRunText->append('}');
2091  m_rExport.m_pParentFrame = nullptr;
2092  }
2093  break;
2094  case ww8::Frame::eDrawing:
2095  {
2096  const SdrObject* pSdrObj = rFrame.GetFrameFormat().FindRealSdrObject();
2097  if (pSdrObj)
2098  {
2099  m_aRunText->append("{" OOO_STRING_SVTOOLS_RTF_FIELD "{");
2100  m_aRunText->append(OOO_STRING_SVTOOLS_RTF_IGNORE);
2101  m_aRunText->append(OOO_STRING_SVTOOLS_RTF_FLDINST);
2102  m_aRunText->append(" SHAPE ");
2103  m_aRunText->append("}"
2105 
2106  m_rExport.SdrExporter().AddSdrObject(*pSdrObj);
2107 
2108  m_aRunText->append('}');
2109  m_aRunText->append('}');
2110  }
2111  }
2112  break;
2114  {
2115  const SwFrameFormat& rFrameFormat = rFrame.GetFrameFormat();
2116  const SdrObject* pObject = rFrameFormat.FindRealSdrObject();
2117 
2118  m_aRun->append("{" OOO_STRING_SVTOOLS_RTF_FIELD);
2120 
2121  if (pObject && pObject->GetObjInventor() == SdrInventor::FmForm)
2122  {
2123  if (auto pFormObj = dynamic_cast<const SdrUnoObj*>(pObject))
2124  {
2125  const uno::Reference<awt::XControlModel>& xControlModel
2126  = pFormObj->GetUnoControlModel();
2127  uno::Reference<lang::XServiceInfo> xInfo(xControlModel, uno::UNO_QUERY);
2128  if (xInfo.is())
2129  {
2130  uno::Reference<beans::XPropertySet> xPropSet(xControlModel, uno::UNO_QUERY);
2131  uno::Reference<beans::XPropertySetInfo> xPropSetInfo
2132  = xPropSet->getPropertySetInfo();
2133  OUString sName;
2134  if (xInfo->supportsService("com.sun.star.form.component.CheckBox"))
2135  {
2137  m_rExport.GetCurrentEncoding()));
2138  m_aRun->append(
2140  "{");
2141  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFTYPE "1"); // 1 = checkbox
2142  // checkbox size in half points, this seems to be always 20
2143  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFHPS "20");
2144 
2145  OUString aStr;
2146  sName = "Name";
2147  if (xPropSetInfo->hasPropertyByName(sName))
2148  {
2149  xPropSet->getPropertyValue(sName) >>= aStr;
2150  m_aRun->append(
2152  " ");
2153  m_aRun->append(
2154  OUStringToOString(aStr, m_rExport.GetCurrentEncoding()));
2155  m_aRun->append('}');
2156  }
2157 
2158  sName = "HelpText";
2159  if (xPropSetInfo->hasPropertyByName(sName))
2160  {
2161  xPropSet->getPropertyValue(sName) >>= aStr;
2162  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFOWNHELP);
2163  m_aRun->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE
2165  m_aRun->append(
2166  OUStringToOString(aStr, m_rExport.GetCurrentEncoding()));
2167  m_aRun->append('}');
2168  }
2169 
2170  sName = "HelpF1Text";
2171  if (xPropSetInfo->hasPropertyByName(sName))
2172  {
2173  xPropSet->getPropertyValue(sName) >>= aStr;
2174  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFOWNSTAT);
2175  m_aRun->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE
2177  m_aRun->append(
2178  OUStringToOString(aStr, m_rExport.GetCurrentEncoding()));
2179  m_aRun->append('}');
2180  }
2181 
2182  sal_Int16 nTemp = 0;
2183  xPropSet->getPropertyValue("DefaultState") >>= nTemp;
2184  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFDEFRES);
2185  m_aRun->append(static_cast<sal_Int32>(nTemp));
2186  xPropSet->getPropertyValue("State") >>= nTemp;
2187  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFRES);
2188  m_aRun->append(static_cast<sal_Int32>(nTemp));
2189 
2190  m_aRun->append("}}");
2191 
2192  // field result is empty, ffres already contains the form result
2193  m_aRun->append("}{" OOO_STRING_SVTOOLS_RTF_FLDRSLT " ");
2194  }
2195  else if (xInfo->supportsService("com.sun.star.form.component.TextField"))
2196  {
2197  OStringBuffer aBuf;
2198  OString aStr;
2199  OUString aTmp;
2200  const char* pStr;
2201 
2203  m_rExport.GetCurrentEncoding()));
2204  m_aRun->append(
2206  " ");
2207  for (int i = 0; i < 8; i++)
2208  aBuf.append(char(0x00));
2209  xPropSet->getPropertyValue("Name") >>= aTmp;
2210  aStr = OUStringToOString(aTmp, m_rExport.GetCurrentEncoding());
2211  aBuf.append(static_cast<char>(aStr.getLength()));
2212  aBuf.append(aStr);
2213  aBuf.append(char(0x00));
2214  xPropSet->getPropertyValue("DefaultText") >>= aTmp;
2215  aStr = OUStringToOString(aTmp, m_rExport.GetCurrentEncoding());
2216  aBuf.append(static_cast<char>(aStr.getLength()));
2217  aBuf.append(aStr);
2218  for (int i = 0; i < 11; i++)
2219  aBuf.append(char(0x00));
2220  aStr = aBuf.makeStringAndClear();
2221  pStr = aStr.getStr();
2222  for (int i = 0; i < aStr.getLength(); i++, pStr++)
2223  m_aRun->append(msfilter::rtfutil::OutHex(*pStr, 2));
2224  m_aRun->append('}');
2225  m_aRun->append("}{" OOO_STRING_SVTOOLS_RTF_FLDRSLT " ");
2226  xPropSet->getPropertyValue("Text") >>= aTmp;
2227  m_aRun->append(OUStringToOString(aTmp, m_rExport.GetCurrentEncoding()));
2228  m_aRun->append('}');
2229  m_aRun->append(
2231  "{");
2232  sName = "HelpText";
2233  if (xPropSetInfo->hasPropertyByName(sName))
2234  {
2235  xPropSet->getPropertyValue(sName) >>= aTmp;
2236  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFOWNHELP);
2237  m_aRun->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE
2239  m_aRun->append(
2240  OUStringToOString(aTmp, m_rExport.GetCurrentEncoding()));
2241  m_aRun->append('}');
2242  }
2243 
2244  sName = "HelpF1Text";
2245  if (xPropSetInfo->hasPropertyByName(sName))
2246  {
2247  xPropSet->getPropertyValue(sName) >>= aTmp;
2248  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFOWNSTAT);
2249  m_aRun->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE
2251  m_aRun->append(
2252  OUStringToOString(aTmp, m_rExport.GetCurrentEncoding()));
2253  m_aRun->append('}');
2254  }
2255  m_aRun->append("}");
2256  }
2257  else if (xInfo->supportsService("com.sun.star.form.component.ListBox"))
2258  {
2259  OUString aStr;
2260  uno::Sequence<sal_Int16> aIntSeq;
2261  uno::Sequence<OUString> aStrSeq;
2262 
2264  m_rExport.GetCurrentEncoding()));
2265  m_aRun->append(
2267  "{");
2268  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFTYPE "2"); // 2 = list
2269  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFHASLISTBOX);
2270 
2271  xPropSet->getPropertyValue("DefaultSelection") >>= aIntSeq;
2272  if (aIntSeq.hasElements())
2273  {
2274  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFDEFRES);
2275  // a dropdown list can have only one 'selected item by default'
2276  m_aRun->append(static_cast<sal_Int32>(aIntSeq[0]));
2277  }
2278 
2279  xPropSet->getPropertyValue("SelectedItems") >>= aIntSeq;
2280  if (aIntSeq.hasElements())
2281  {
2282  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFRES);
2283  // a dropdown list can have only one 'currently selected item'
2284  m_aRun->append(static_cast<sal_Int32>(aIntSeq[0]));
2285  }
2286 
2287  sName = "Name";
2288  if (xPropSetInfo->hasPropertyByName(sName))
2289  {
2290  xPropSet->getPropertyValue(sName) >>= aStr;
2291  m_aRun->append(
2293  " ");
2294  m_aRun->append(
2295  OUStringToOString(aStr, m_rExport.GetCurrentEncoding()));
2296  m_aRun->append('}');
2297  }
2298 
2299  sName = "HelpText";
2300  if (xPropSetInfo->hasPropertyByName(sName))
2301  {
2302  xPropSet->getPropertyValue(sName) >>= aStr;
2303  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFOWNHELP);
2304  m_aRun->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE
2306  m_aRun->append(
2307  OUStringToOString(aStr, m_rExport.GetCurrentEncoding()));
2308  m_aRun->append('}');
2309  }
2310 
2311  sName = "HelpF1Text";
2312  if (xPropSetInfo->hasPropertyByName(sName))
2313  {
2314  xPropSet->getPropertyValue(sName) >>= aStr;
2315  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFOWNSTAT);
2316  m_aRun->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE
2318  m_aRun->append(
2319  OUStringToOString(aStr, m_rExport.GetCurrentEncoding()));
2320  m_aRun->append('}');
2321  }
2322 
2323  xPropSet->getPropertyValue("StringItemList") >>= aStrSeq;
2324  for (const auto& rStr : std::as_const(aStrSeq))
2325  m_aRun->append(
2327  + OUStringToOString(rStr, m_rExport.GetCurrentEncoding())
2328  + "}");
2329 
2330  m_aRun->append("}}");
2331 
2332  // field result is empty, ffres already contains the form result
2333  m_aRun->append("}{" OOO_STRING_SVTOOLS_RTF_FLDRSLT " ");
2334  }
2335  else
2336  SAL_INFO("sw.rtf", __func__ << " unhandled form control: '"
2337  << xInfo->getImplementationName() << "'");
2338  m_aRun->append('}');
2339  }
2340  }
2341  }
2342 
2343  m_aRun->append('}');
2344  }
2345  break;
2346  case ww8::Frame::eOle:
2347  {
2348  const SwFrameFormat& rFrameFormat = rFrame.GetFrameFormat();
2349  const SdrObject* pSdrObj = rFrameFormat.FindRealSdrObject();
2350  if (pSdrObj)
2351  {
2352  SwNodeIndex aIdx(*rFrameFormat.GetContent().GetContentIdx(), 1);
2353  SwOLENode& rOLENd = *aIdx.GetNode().GetOLENode();
2354  FlyFrameOLE(dynamic_cast<const SwFlyFrameFormat*>(&rFrameFormat), rOLENd,
2355  rFrame.GetLayoutSize());
2356  }
2357  }
2358  break;
2359  default:
2360  SAL_INFO("sw.rtf", __func__ << ": unknown type ("
2361  << static_cast<int>(rFrame.GetWriterType()) << ")");
2362  break;
2363  }
2364 }
2365 
2367 {
2368  switch (rCaseMap.GetValue())
2369  {
2370  case SvxCaseMap::SmallCaps:
2371  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SCAPS);
2372  break;
2373  case SvxCaseMap::Uppercase:
2374  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_CAPS);
2375  break;
2376  default: // Something that rtf does not support
2377  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SCAPS);
2378  m_aStyles.append(sal_Int32(0));
2379  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_CAPS);
2380  m_aStyles.append(sal_Int32(0));
2381  break;
2382  }
2383 }
2384 
2386 {
2387  const Color aColor(rColor.GetValue());
2388 
2389  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_CF);
2390  m_aStyles.append(static_cast<sal_Int32>(m_rExport.GetColor(aColor)));
2391 }
2392 
2394 {
2395  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_OUTL);
2396  if (!rContour.GetValue())
2397  m_aStyles.append(sal_Int32(0));
2398 }
2399 
2401 {
2402  switch (rCrossedOut.GetStrikeout())
2403  {
2404  case STRIKEOUT_NONE:
2405  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_STRIKE);
2406  m_aStyles.append(sal_Int32(0));
2407  break;
2408  case STRIKEOUT_DOUBLE:
2409  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_STRIKED);
2410  m_aStyles.append(sal_Int32(1));
2411  break;
2412  default:
2413  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_STRIKE);
2414  break;
2415  }
2416 }
2417 
2419 {
2420  short nEsc = rEscapement.GetEsc();
2421  short nProp = rEscapement.GetProportionalHeight();
2422  sal_Int32 nProp100 = nProp * 100;
2423  if (DFLT_ESC_PROP == nProp || nProp < 1 || nProp > 100)
2424  {
2425  if (DFLT_ESC_SUB == nEsc || DFLT_ESC_AUTO_SUB == nEsc)
2426  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SUB);
2427  else if (DFLT_ESC_SUPER == nEsc || DFLT_ESC_AUTO_SUPER == nEsc)
2428  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SUPER);
2429  return;
2430  }
2431  if (DFLT_ESC_AUTO_SUPER == nEsc)
2432  {
2433  nEsc = .8 * (100 - nProp);
2434  ++nProp100; // A 1 afterwards means 'automatic' according to editeng/rtf/rtfitem.cxx
2435  }
2436  else if (DFLT_ESC_AUTO_SUB == nEsc)
2437  {
2438  nEsc = .2 * -(100 - nProp);
2439  ++nProp100;
2440  }
2441 
2442  const char* pUpDn;
2443 
2444  double fHeight = m_rExport.GetItem(RES_CHRATR_FONTSIZE).GetHeight();
2445 
2446  if (0 < nEsc)
2447  pUpDn = OOO_STRING_SVTOOLS_RTF_UP;
2448  else if (0 > nEsc)
2449  {
2450  pUpDn = OOO_STRING_SVTOOLS_RTF_DN;
2451  fHeight = -fHeight;
2452  }
2453  else
2454  return;
2455 
2456  m_aStyles.append('{');
2457  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_IGNORE);
2458  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_UPDNPROP);
2459  m_aStyles.append(nProp100);
2460  m_aStyles.append('}');
2461  m_aStyles.append(pUpDn);
2462 
2463  /*
2464  * Calculate the act. FontSize and the percentage of the displacement;
2465  * RTF file expects half points, while internally it's in twips.
2466  * Formally : (FontSize * 1/20 ) pts x * 2
2467  * ----------------------- = ------------
2468  * 100% Escapement
2469  */
2470  m_aStyles.append(static_cast<sal_Int32>(round(fHeight * nEsc / 1000)));
2471 }
2472 
2474 {
2475  // Insert \loch in MoveCharacterProperties
2476  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_F);
2477  m_aStyles.append(static_cast<sal_Int32>(m_rExport.m_aFontHelper.GetId(rFont)));
2478 
2479  // Insert \hich in MoveCharacterProperties
2480  m_aStylesAssocHich.append(OOO_STRING_SVTOOLS_RTF_AF);
2481  m_aStylesAssocHich.append(static_cast<sal_Int32>(m_rExport.m_aFontHelper.GetId(rFont)));
2482 
2483  // FIXME: this may be a tad expensive... but the charset needs to be
2484  // consistent with what wwFont::WriteRtf() does
2485  sw::util::FontMapExport aTmp(rFont.GetFamilyName());
2487  aTmp.msPrimary, aTmp.msSecondary, rFont.GetCharSet());
2488  m_rExport.SetCurrentEncoding(rtl_getTextEncodingFromWindowsCharset(nWindowsCharset));
2489  if (m_rExport.GetCurrentEncoding() == RTL_TEXTENCODING_DONTKNOW)
2490  m_rExport.SetCurrentEncoding(m_rExport.GetDefaultEncoding());
2491 }
2492 
2494 {
2495  switch (rFontSize.Which())
2496  {
2497  case RES_CHRATR_FONTSIZE:
2498  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_FS);
2499  m_aStyles.append(static_cast<sal_Int32>(rFontSize.GetHeight() / 10));
2500  break;
2502  m_aStylesAssocDbch.append(OOO_STRING_SVTOOLS_RTF_AFS);
2503  m_aStylesAssocDbch.append(static_cast<sal_Int32>(rFontSize.GetHeight() / 10));
2504  break;
2506  m_aStylesAssocRtlch.append(OOO_STRING_SVTOOLS_RTF_AFS);
2507  m_aStylesAssocRtlch.append(static_cast<sal_Int32>(rFontSize.GetHeight() / 10));
2508  break;
2509  }
2510 }
2511 
2513 {
2514  // in quarter points then in twips
2515  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_EXPND);
2516  m_aStyles.append(static_cast<sal_Int32>(rKerning.GetValue() / 5));
2517  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_EXPNDTW);
2518  m_aStyles.append(static_cast<sal_Int32>(rKerning.GetValue()));
2519 }
2520 
2522 {
2523  switch (rLanguage.Which())
2524  {
2525  case RES_CHRATR_LANGUAGE:
2526  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_LANG);
2527  m_aStyles.append(
2528  static_cast<sal_Int32>(static_cast<sal_uInt16>(rLanguage.GetLanguage())));
2529  m_aStylesAssocLtrch.append(OOO_STRING_SVTOOLS_RTF_LANG);
2530  m_aStylesAssocLtrch.append(
2531  static_cast<sal_Int32>(static_cast<sal_uInt16>(rLanguage.GetLanguage())));
2532  break;
2534  m_aStylesAssocDbch.append(OOO_STRING_SVTOOLS_RTF_LANGFE);
2535  m_aStylesAssocDbch.append(
2536  static_cast<sal_Int32>(static_cast<sal_uInt16>(rLanguage.GetLanguage())));
2537  m_aStylesAssocLtrch.append(OOO_STRING_SVTOOLS_RTF_LANGFE);
2538  m_aStylesAssocLtrch.append(
2539  static_cast<sal_Int32>(static_cast<sal_uInt16>(rLanguage.GetLanguage())));
2540  break;
2542  m_aStylesAssocRtlch.append(OOO_STRING_SVTOOLS_RTF_ALANG);
2543  m_aStylesAssocRtlch.append(
2544  static_cast<sal_Int32>(static_cast<sal_uInt16>(rLanguage.GetLanguage())));
2545  break;
2546  }
2547 }
2548 
2550 {
2551  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_I);
2552  if (rPosture.GetPosture() == ITALIC_NONE)
2553  m_aStyles.append(sal_Int32(0));
2554 }
2555 
2557 {
2558  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SHAD);
2559  if (!rShadow.GetValue())
2560  m_aStyles.append(sal_Int32(0));
2561 }
2562 
2564 {
2565  const char* pStr = nullptr;
2566  const SfxPoolItem* pItem = m_rExport.HasItem(RES_CHRATR_WORDLINEMODE);
2567  bool bWord = false;
2568  // No StaticWhichCast(RES_CHRATR_WORDLINEMODE), this may be for a postit, where the which ids
2569  // don't match.
2570  if (pItem)
2571  bWord = static_cast<const SvxWordLineModeItem*>(pItem)->GetValue();
2572  switch (rUnderline.GetLineStyle())
2573  {
2574  case LINESTYLE_SINGLE:
2576  break;
2577  case LINESTYLE_DOUBLE:
2579  break;
2580  case LINESTYLE_NONE:
2582  break;
2583  case LINESTYLE_DOTTED:
2585  break;
2586  case LINESTYLE_DASH:
2588  break;
2589  case LINESTYLE_DASHDOT:
2591  break;
2592  case LINESTYLE_DASHDOTDOT:
2594  break;
2595  case LINESTYLE_BOLD:
2597  break;
2598  case LINESTYLE_WAVE:
2600  break;
2601  case LINESTYLE_BOLDDOTTED:
2603  break;
2604  case LINESTYLE_BOLDDASH:
2606  break;
2607  case LINESTYLE_LONGDASH:
2609  break;
2612  break;
2613  case LINESTYLE_BOLDDASHDOT:
2615  break;
2618  break;
2619  case LINESTYLE_BOLDWAVE:
2621  break;
2622  case LINESTYLE_DOUBLEWAVE:
2624  break;
2625  default:
2626  break;
2627  }
2628 
2629  if (pStr)
2630  {
2631  m_aStyles.append(pStr);
2632  // NEEDSWORK looks like here rUnderline.GetColor() is always black,
2633  // even if the color in the odt is for example green...
2634  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ULC);
2635  m_aStyles.append(static_cast<sal_Int32>(m_rExport.GetColor(rUnderline.GetColor())));
2636  }
2637 }
2638 
2640 {
2641  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_B);
2642  if (rWeight.GetWeight() != WEIGHT_BOLD)
2643  m_aStyles.append(sal_Int32(0));
2644 }
2645 
2647 {
2648  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_KERNING);
2649  m_aStyles.append(static_cast<sal_Int32>(rAutoKern.GetValue() ? 1 : 0));
2650 }
2651 
2653 {
2654  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ANIMTEXT);
2655  m_aStyles.append(static_cast<sal_Int32>(rBlink.GetValue() ? 2 : 0));
2656 }
2657 
2659 {
2660  if (!rBrush.GetColor().IsTransparent())
2661  {
2662  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_CHCBPAT);
2663  m_aStyles.append(static_cast<sal_Int32>(m_rExport.GetColor(rBrush.GetColor())));
2664  }
2665 }
2666 
2668 {
2669  // Insert \dbch in MoveCharacterProperties
2670  m_aStylesAssocDbch.append(OOO_STRING_SVTOOLS_RTF_AF);
2671  m_aStylesAssocDbch.append(static_cast<sal_Int32>(m_rExport.m_aFontHelper.GetId(rFont)));
2672 }
2673 
2675 {
2676  CharFontSize(rFontSize);
2677 }
2678 
2680 {
2681  CharLanguage(rLanguageItem);
2682 }
2683 
2685 {
2686  m_aStylesAssocDbch.append(OOO_STRING_SVTOOLS_RTF_I);
2687  if (rPosture.GetPosture() == ITALIC_NONE)
2688  m_aStylesAssocDbch.append(sal_Int32(0));
2689 }
2690 
2692 {
2693  m_aStylesAssocDbch.append(OOO_STRING_SVTOOLS_RTF_AB);
2694  if (rWeight.GetWeight() != WEIGHT_BOLD)
2695  m_aStylesAssocDbch.append(sal_Int32(0));
2696 }
2697 
2699 {
2700  // Insert \rtlch in MoveCharacterProperties
2701  m_aStylesAssocRtlch.append(OOO_STRING_SVTOOLS_RTF_AF);
2702  m_aStylesAssocRtlch.append(static_cast<sal_Int32>(m_rExport.m_aFontHelper.GetId(rFont)));
2703 }
2704 
2706 {
2707  CharFontSize(rFontSize);
2708 }
2709 
2711 {
2712  CharLanguage(rLanguageItem);
2713 }
2714 
2716 {
2717  m_aStylesAssocRtlch.append(OOO_STRING_SVTOOLS_RTF_AI);
2718  if (rPosture.GetPosture() == ITALIC_NONE)
2719  m_aStylesAssocRtlch.append(sal_Int32(0));
2720 }
2721 
2723 {
2724  m_aStylesAssocRtlch.append(OOO_STRING_SVTOOLS_RTF_AB);
2725  if (rWeight.GetWeight() != WEIGHT_BOLD)
2726  m_aStylesAssocRtlch.append(sal_Int32(0));
2727 }
2728 
2730 
2732 
2734 {
2735  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_HORZVERT);
2736  m_aStyles.append(static_cast<sal_Int32>(rRotate.IsFitToLine() ? 1 : 0));
2737 }
2738 
2740 {
2741  FontEmphasisMark v = rEmphasisMark.GetEmphasisMark();
2742  if (v == FontEmphasisMark::NONE)
2743  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ACCNONE);
2744  else if (v == (FontEmphasisMark::Dot | FontEmphasisMark::PosAbove))
2745  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ACCDOT);
2746  else if (v == (FontEmphasisMark::Accent | FontEmphasisMark::PosAbove))
2747  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ACCCOMMA);
2748  else if (v == (FontEmphasisMark::Circle | FontEmphasisMark::PosAbove))
2749  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ACCCIRCLE);
2750  else if (v == (FontEmphasisMark::Dot | FontEmphasisMark::PosBelow))
2751  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ACCUNDERDOT);
2752 }
2753 
2755 {
2756  if (!rTwoLines.GetValue())
2757  return;
2758 
2759  sal_Unicode cStart = rTwoLines.GetStartBracket();
2760  sal_Unicode cEnd = rTwoLines.GetEndBracket();
2761 
2762  sal_uInt16 nType;
2763  if (!cStart && !cEnd)
2764  nType = 0;
2765  else if ('{' == cStart || '}' == cEnd)
2766  nType = 4;
2767  else if ('<' == cStart || '>' == cEnd)
2768  nType = 3;
2769  else if ('[' == cStart || ']' == cEnd)
2770  nType = 2;
2771  else // all other kind of brackets
2772  nType = 1;
2773 
2774  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_TWOINONE);
2775  m_aStyles.append(static_cast<sal_Int32>(nType));
2776 }
2777 
2779 {
2780  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_CHARSCALEX);
2781  m_aStyles.append(static_cast<sal_Int32>(rScaleWidth.GetValue()));
2782 }
2783 
2785 {
2786  const char* pStr;
2787  switch (rRelief.GetValue())
2788  {
2789  case FontRelief::Embossed:
2791  break;
2792  case FontRelief::Engraved:
2794  break;
2795  default:
2796  pStr = nullptr;
2797  break;
2798  }
2799 
2800  if (pStr)
2801  m_aStyles.append(pStr);
2802 }
2803 
2805 {
2806  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_V);
2807  if (!rHidden.GetValue())
2808  m_aStyles.append(sal_Int32(0));
2809 }
2810 
2812  const sal_uInt16 nDist, const bool bShadow)
2813 {
2814  m_aStyles.append(
2815  OutBorderLine(m_rExport, pAllBorder, OOO_STRING_SVTOOLS_RTF_CHBRDR, nDist,
2816  bShadow ? SvxShadowLocation::BottomRight : SvxShadowLocation::NONE));
2817 }
2818 
2820 {
2821  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_HIGHLIGHT);
2822  m_aStyles.append(static_cast<sal_Int32>(msfilter::util::TransColToIco(rBrush.GetColor())));
2823 }
2824 
2826 {
2827  if (rURL.GetValue().isEmpty())
2828  return;
2829 
2830  const SwCharFormat* pFormat;
2831  const SwTextINetFormat* pTextAtr = rURL.GetTextINetFormat();
2832 
2833  if (pTextAtr && nullptr != (pFormat = pTextAtr->GetCharFormat()))
2834  {
2835  sal_uInt16 nStyle = m_rExport.GetId(pFormat);
2836  OString* pString = m_rExport.GetStyle(nStyle);
2837  if (pString)
2838  m_aStyles.append(*pString);
2839  }
2840 }
2841 
2843 {
2844  sal_uInt16 nStyle = m_rExport.GetId(rCharFormat.GetCharFormat());
2845  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_CS);
2846  m_aStyles.append(static_cast<sal_Int32>(nStyle));
2847  OString* pString = m_rExport.GetStyle(nStyle);
2848  if (pString)
2849  m_aStyles.append(*pString);
2850 }
2851 
2853 {
2854  if (rFootnote.GetNumStr().isEmpty())
2855  m_aRun->append(OOO_STRING_SVTOOLS_RTF_CHFTN);
2856  else
2857  m_aRun->append(
2858  msfilter::rtfutil::OutString(rFootnote.GetNumStr(), m_rExport.GetCurrentEncoding()));
2859 }
2860 
2862 {
2863  SAL_INFO("sw.rtf", __func__ << " start");
2864 
2865  m_aRun->append("{" OOO_STRING_SVTOOLS_RTF_SUPER " ");
2866  EndRunProperties(nullptr);
2867  m_aRun->append(' ');
2868  WriteTextFootnoteNumStr(rFootnote);
2870  if (rFootnote.IsEndNote() || m_rExport.m_rDoc.GetFootnoteInfo().m_ePos == FTNPOS_CHAPTER)
2871  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FTNALT);
2872  m_aRun->append(' ');
2873  WriteTextFootnoteNumStr(rFootnote);
2874 
2875  /*
2876  * The footnote contains a whole paragraph, so we have to:
2877  * 1) Reset, then later restore the contents of our run buffer and run state.
2878  * 2) Buffer the output of the whole paragraph, as we do so for section headers already.
2879  */
2880  const SwNodeIndex* pIndex = rFootnote.GetTextFootnote()->GetStartNode();
2881  RtfStringBuffer aRun = m_aRun;
2882  m_aRun.clear();
2883  bool bInRunOrig = m_bInRun;
2884  m_bInRun = false;
2885  bool bSingleEmptyRunOrig = m_bSingleEmptyRun;
2886  m_bSingleEmptyRun = false;
2887  m_bBufferSectionHeaders = true;
2888  m_rExport.WriteSpecialText(pIndex->GetIndex() + 1, pIndex->GetNode().EndOfSectionIndex(),
2889  !rFootnote.IsEndNote() ? TXT_FTN : TXT_EDN);
2890  m_bBufferSectionHeaders = false;
2891  m_bInRun = bInRunOrig;
2892  m_bSingleEmptyRun = bSingleEmptyRunOrig;
2893  m_aRun = aRun;
2894  m_aRun->append(m_aSectionHeaders.makeStringAndClear());
2895 
2896  m_aRun->append("}");
2897  m_aRun->append("}");
2898 
2899  SAL_INFO("sw.rtf", __func__ << " end");
2900 }
2901 
2902 void RtfAttributeOutput::ParaLineSpacing_Impl(short nSpace, short nMulti)
2903 {
2904  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SL);
2905  m_aStyles.append(static_cast<sal_Int32>(nSpace));
2906  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SLMULT);
2907  m_aStyles.append(static_cast<sal_Int32>(nMulti));
2908 }
2909 
2911 {
2912  switch (rAdjust.GetAdjust())
2913  {
2914  case SvxAdjust::Left:
2915  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_QL);
2916  break;
2917  case SvxAdjust::Right:
2918  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_QR);
2919  break;
2920  case SvxAdjust::BlockLine:
2921  case SvxAdjust::Block:
2922  if (rAdjust.GetLastBlock() == SvxAdjust::Block)
2923  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_QD);
2924  else
2925  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_QJ);
2926  break;
2927  case SvxAdjust::Center:
2928  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_QC);
2929  break;
2930  default:
2931  break;
2932  }
2933 }
2934 
2936 {
2937  if (!rSplit.GetValue())
2938  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_KEEP);
2939 }
2940 
2942 {
2943  if (rWidows.GetValue())
2944  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_WIDCTLPAR);
2945  else
2946  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_NOWIDCTLPAR);
2947 }
2948 
2950 {
2951  tools::Long nOffset = 0;
2952  // Tabs are absolute by default.
2953  if (m_rExport.m_rDoc.getIDocumentSettingAccess().get(
2955  nOffset = m_rExport.GetItem(RES_LR_SPACE).GetTextLeft();
2956 
2957  for (sal_uInt16 n = 0; n < rTabStop.Count(); n++)
2958  {
2959  const SvxTabStop& rTS = rTabStop[n];
2960  if (SvxTabAdjust::Default != rTS.GetAdjustment())
2961  {
2962  const char* pFill = nullptr;
2963  switch (rTS.GetFill())
2964  {
2965  case cDfltFillChar:
2966  break;
2967 
2968  case '.':
2970  break;
2971  case '_':
2973  break;
2974  case '-':
2976  break;
2977  case '=':
2979  break;
2980  default:
2981  break;
2982  }
2983  if (pFill)
2984  m_aStyles.append(pFill);
2985 
2986  const char* pAdjStr = nullptr;
2987  switch (rTS.GetAdjustment())
2988  {
2989  case SvxTabAdjust::Right:
2990  pAdjStr = OOO_STRING_SVTOOLS_RTF_TQR;
2991  break;
2992  case SvxTabAdjust::Decimal:
2993  pAdjStr = OOO_STRING_SVTOOLS_RTF_TQDEC;
2994  break;
2995  case SvxTabAdjust::Center:
2996  pAdjStr = OOO_STRING_SVTOOLS_RTF_TQC;
2997  break;
2998  default:
2999  break;
3000  }
3001  if (pAdjStr)
3002  m_aStyles.append(pAdjStr);
3003  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_TX);
3004  m_aStyles.append(static_cast<sal_Int32>(rTS.GetTabPos() + nOffset));
3005  }
3006  else
3007  {
3008  m_aTabStop.append(OOO_STRING_SVTOOLS_RTF_DEFTAB);
3009  m_aTabStop.append(rTabStop[0].GetTabPos());
3010  }
3011  }
3012 }
3013 
3015 {
3016  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_HYPHPAR);
3017  m_aStyles.append(sal_Int32(rHyphenZone.IsHyphen()));
3018 }
3019 
3020 void RtfAttributeOutput::ParaNumRule_Impl(const SwTextNode* pTextNd, sal_Int32 nLvl,
3021  sal_Int32 nNumId)
3022 {
3023  if (USHRT_MAX == nNumId || 0 == nNumId || nullptr == pTextNd)
3024  return;
3025 
3026  const SwNumRule* pRule = pTextNd->GetNumRule();
3027 
3028  if (!pRule || !pTextNd->IsInList())
3029  return;
3030 
3031  SAL_WARN_IF(pTextNd->GetActualListLevel() < 0 || pTextNd->GetActualListLevel() >= MAXLEVEL,
3032  "sw.rtf", "text node does not have valid list level");
3033 
3034  const SwNumFormat* pFormat = pRule->GetNumFormat(nLvl);
3035  if (!pFormat)
3036  pFormat = &pRule->Get(nLvl);
3037 
3038  const SfxItemSet& rNdSet = pTextNd->GetSwAttrSet();
3039 
3040  m_aStyles.append('{');
3041  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_LISTTEXT);
3042  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_PARD);
3043  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_PLAIN);
3044  m_aStyles.append(' ');
3045 
3046  SvxLRSpaceItem aLR(rNdSet.Get(RES_LR_SPACE));
3047  aLR.SetTextLeft(aLR.GetTextLeft() + pFormat->GetIndentAt());
3048  aLR.SetTextFirstLineOffset(pFormat->GetFirstLineOffset()); //TODO: overflow
3049 
3050  sal_uInt16 nStyle = m_rExport.GetId(pFormat->GetCharFormat());
3051  OString* pString = m_rExport.GetStyle(nStyle);
3052  if (pString)
3053  m_aStyles.append(*pString);
3054 
3055  {
3056  OUString sText;
3057  if (SVX_NUM_CHAR_SPECIAL == pFormat->GetNumberingType()
3058  || SVX_NUM_BITMAP == pFormat->GetNumberingType())
3059  {
3060  sal_UCS4 cBullet = pFormat->GetBulletChar();
3061  sText = OUString(&cBullet, 1);
3062  }
3063  else
3064  sText = pTextNd->GetNumString();
3065 
3066  if (!sText.isEmpty())
3067  {
3068  m_aStyles.append(' ');
3069  m_aStyles.append(msfilter::rtfutil::OutString(sText, m_rExport.GetDefaultEncoding()));
3070  }
3071 
3072  if (OUTLINE_RULE != pRule->GetRuleType())
3073  {
3074  if (!sText.isEmpty())
3075  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_TAB);
3076  m_aStyles.append('}');
3077  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ILVL);
3078  if (nLvl > 8) // RTF knows only 9 levels
3079  {
3080  m_aStyles.append(sal_Int32(8));
3082  m_aStyles.append(nLvl);
3083  m_aStyles.append('}');
3084  }
3085  else
3086  m_aStyles.append(nLvl);
3087  }
3088  else
3089  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_TAB "}");
3090  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_LS);
3091  m_aStyles.append(static_cast<sal_Int32>(m_rExport.GetNumberingId(*pRule)) + 1);
3092  m_aStyles.append(' ');
3093  }
3094  FormatLRSpace(aLR);
3095 }
3096 
3098 {
3099  if (!rScriptSpace.GetValue())
3100  return;
3101 
3102  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ASPALPHA);
3103 }
3104 
3106 {
3107  SAL_INFO("sw.rtf", "TODO: " << __func__);
3108 }
3109 
3111 {
3112  SAL_INFO("sw.rtf", "TODO: " << __func__);
3113 }
3114 
3116 {
3117  const char* pStr;
3118  switch (rAlign.GetValue())
3119  {
3122  break;
3125  break;
3128  break;
3131  break;
3132 
3133  default:
3135  break;
3136  }
3137  m_aStyles.append(pStr);
3138 }
3139 
3141 {
3142  SAL_INFO("sw.rtf", "TODO: " << __func__);
3143 }
3144 
3146 {
3147  if (m_rExport.m_bOutPageDescs)
3148  {
3149  m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_PGWSXN);
3150  m_aSectionBreaks.append(static_cast<sal_Int32>(rSize.GetWidth()));
3151  m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_PGHSXN);
3152  m_aSectionBreaks.append(static_cast<sal_Int32>(rSize.GetHeight()));
3153  if (!m_bBufferSectionBreaks)
3154  m_rExport.Strm().WriteOString(m_aSectionBreaks.makeStringAndClear());
3155  }
3156 }
3157 
3159 {
3160  SAL_INFO("sw.rtf", "TODO: " << __func__);
3161 }
3162 
3164 {
3165  if (!m_rExport.m_bOutFlyFrameAttrs)
3166  {
3167  if (m_rExport.m_bOutPageDescs)
3168  {
3169  if (rLRSpace.GetLeft())
3170  {
3171  m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_MARGLSXN);
3172  m_aSectionBreaks.append(static_cast<sal_Int32>(rLRSpace.GetLeft()));
3173  }
3174  if (rLRSpace.GetRight())
3175  {
3176  m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_MARGRSXN);
3177  m_aSectionBreaks.append(static_cast<sal_Int32>(rLRSpace.GetRight()));
3178  }
3179  if (rLRSpace.GetGutterMargin())
3180  {
3181  m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_GUTTER);
3182  m_aSectionBreaks.append(static_cast<sal_Int32>(rLRSpace.GetGutterMargin()));
3183  }
3184  if (!m_bBufferSectionBreaks)
3185  m_rExport.Strm().WriteOString(m_aSectionBreaks.makeStringAndClear());
3186  }
3187  else
3188  {
3189  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_LI);
3190  m_aStyles.append(static_cast<sal_Int32>(rLRSpace.GetTextLeft()));
3191  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_RI);
3192  m_aStyles.append(static_cast<sal_Int32>(rLRSpace.GetRight()));
3193  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_LIN);
3194  m_aStyles.append(static_cast<sal_Int32>(rLRSpace.GetTextLeft()));
3195  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_RIN);
3196  m_aStyles.append(static_cast<sal_Int32>(rLRSpace.GetRight()));
3197  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_FI);
3198  m_aStyles.append(static_cast<sal_Int32>(rLRSpace.GetTextFirstLineOffset()));
3199  }
3200  }
3201  else if (m_rExport.GetRTFFlySyntax())
3202  {
3203  // Wrap: top and bottom spacing, convert from twips to EMUs.
3204  m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3205  "dxWrapDistLeft", OString::number(o3tl::convert(rLRSpace.GetLeft(), o3tl::Length::twip,
3206  o3tl::Length::emu))));
3207  m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3208  "dxWrapDistRight", OString::number(o3tl::convert(
3210  }
3211 }
3212 
3214 {
3215  if (!m_rExport.m_bOutFlyFrameAttrs)
3216  {
3217  if (m_rExport.m_bOutPageDescs)
3218  {
3219  OSL_ENSURE(m_rExport.GetCurItemSet(), "Impossible");
3220  if (!m_rExport.GetCurItemSet())
3221  return;
3222 
3223  // If we export a follow page format, then our doc model has
3224  // separate header/footer distances for the first page and the
3225  // follow pages, but Word can have only a single distance. In case
3226  // the two values differ, work with the value from the first page
3227  // format to be in sync with the import.
3228  sw::util::HdFtDistanceGlue aDistances(m_rExport.GetFirstPageItemSet()
3229  ? *m_rExport.GetFirstPageItemSet()
3230  : *m_rExport.GetCurItemSet());
3231 
3232  if (aDistances.dyaTop)
3233  {
3234  m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_MARGTSXN);
3235  m_aSectionBreaks.append(static_cast<sal_Int32>(aDistances.dyaTop));
3236  }
3237  if (aDistances.HasHeader())
3238  {
3239  m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_HEADERY);
3240  m_aSectionBreaks.append(static_cast<sal_Int32>(aDistances.dyaHdrTop));
3241  }
3242 
3243  if (aDistances.dyaBottom)
3244  {
3245  m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_MARGBSXN);
3246  m_aSectionBreaks.append(static_cast<sal_Int32>(aDistances.dyaBottom));
3247  }
3248  if (aDistances.HasFooter())
3249  {
3250  m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_FOOTERY);
3251  m_aSectionBreaks.append(static_cast<sal_Int32>(aDistances.dyaHdrBottom));
3252  }
3253  if (!m_bBufferSectionBreaks)
3254  m_rExport.Strm().WriteOString(m_aSectionBreaks.makeStringAndClear());
3255  }
3256  else
3257  {
3258  // Spacing before.
3259  if (m_bParaBeforeAutoSpacing && m_nParaBeforeSpacing == rULSpace.GetUpper())
3260  m_aStyles.append(LO_STRING_SVTOOLS_RTF_SBAUTO "1");
3261  else if (m_bParaBeforeAutoSpacing && m_nParaBeforeSpacing == -1)
3262  {
3263  m_aStyles.append(LO_STRING_SVTOOLS_RTF_SBAUTO "0");
3264  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SB);
3265  m_aStyles.append(static_cast<sal_Int32>(rULSpace.GetUpper()));
3266  }
3267  else
3268  {
3269  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SB);
3270  m_aStyles.append(static_cast<sal_Int32>(rULSpace.GetUpper()));
3271  }
3272  m_bParaBeforeAutoSpacing = false;
3273 
3274  // Spacing after.
3275  if (m_bParaAfterAutoSpacing && m_nParaAfterSpacing == rULSpace.GetLower())
3276  m_aStyles.append(LO_STRING_SVTOOLS_RTF_SAAUTO "1");
3277  else if (m_bParaAfterAutoSpacing && m_nParaAfterSpacing == -1)
3278  {
3279  m_aStyles.append(LO_STRING_SVTOOLS_RTF_SAAUTO "0");
3280  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SA);
3281  m_aStyles.append(static_cast<sal_Int32>(rULSpace.GetLower()));
3282  }
3283  else
3284  {
3285  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SA);
3286  m_aStyles.append(static_cast<sal_Int32>(rULSpace.GetLower()));
3287  }
3288  m_bParaAfterAutoSpacing = false;
3289 
3290  // Contextual spacing.
3291  if (rULSpace.GetContext())
3292  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_CONTEXTUALSPACE);
3293  }
3294  }
3295  else if (m_rExport.GetRTFFlySyntax())
3296  {
3297  // Wrap: top and bottom spacing, convert from twips to EMUs.
3298  m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3299  "dyWrapDistTop", OString::number(o3tl::convert(rULSpace.GetUpper(), o3tl::Length::twip,
3300  o3tl::Length::emu))));
3301  m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3302  "dyWrapDistBottom", OString::number(o3tl::convert(
3304  }
3305 }
3306 
3308 {
3309  if (m_rExport.m_bOutFlyFrameAttrs && !m_rExport.GetRTFFlySyntax())
3310  {
3311  css::text::WrapTextMode eSurround = rSurround.GetSurround();
3312  bool bGold = css::text::WrapTextMode_DYNAMIC == eSurround;
3313  if (bGold)
3314  eSurround = css::text::WrapTextMode_PARALLEL;
3315  RTFSurround aMC(bGold, static_cast<sal_uInt8>(eSurround));
3316  m_aRunText->append(OOO_STRING_SVTOOLS_RTF_FLYMAINCNT);
3317  m_aRunText->append(static_cast<sal_Int32>(aMC.GetValue()));
3318  }
3319  else if (m_rExport.m_bOutFlyFrameAttrs && m_rExport.GetRTFFlySyntax())
3320  {
3321  // See DocxSdrExport::startDMLAnchorInline() for SwFormatSurround -> WR / WRK mappings.
3322  sal_Int32 nWr = -1;
3323  std::optional<sal_Int32> oWrk;
3324  switch (rSurround.GetValue())
3325  {
3326  case css::text::WrapTextMode_NONE:
3327  nWr = 1; // top and bottom
3328  break;
3329  case css::text::WrapTextMode_THROUGH:
3330  nWr = 3; // none
3331  break;
3332  case css::text::WrapTextMode_PARALLEL:
3333  nWr = 2; // around
3334  oWrk = 0; // both sides
3335  break;
3336  case css::text::WrapTextMode_DYNAMIC:
3337  default:
3338  nWr = 2; // around
3339  oWrk = 3; // largest
3340  break;
3341  }
3342 
3343  if (rSurround.IsContour())
3344  nWr = 4; // tight
3345 
3346  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_SHPWR);
3347  m_rExport.OutLong(nWr);
3348  if (oWrk)
3349  {
3350  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_SHPWRK);
3351  m_rExport.OutLong(*oWrk);
3352  }
3353  }
3354 }
3355 
3357 {
3358  if (!(m_rExport.m_bOutFlyFrameAttrs && m_rExport.GetRTFFlySyntax()))
3359  return;
3360 
3361  switch (rFlyVert.GetRelationOrient())
3362  {
3363  case text::RelOrientation::PAGE_FRAME:
3364  m_aFlyProperties.push_back(
3365  std::make_pair<OString, OString>("posrelv", OString::number(1)));
3366  break;
3367  default:
3368  m_aFlyProperties.push_back(
3369  std::make_pair<OString, OString>("posrelv", OString::number(2)));
3370  m_rExport.Strm()
3371  .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_SHPBYPARA)
3372  .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_SHPBYIGNORE);
3373  break;
3374  }
3375 
3376  switch (rFlyVert.GetVertOrient())
3377  {
3378  case text::VertOrientation::TOP:
3379  case text::VertOrientation::LINE_TOP:
3380  m_aFlyProperties.push_back(
3381  std::make_pair<OString, OString>("posv", OString::number(1)));
3382  break;
3383  case text::VertOrientation::BOTTOM:
3384  case text::VertOrientation::LINE_BOTTOM:
3385  m_aFlyProperties.push_back(
3386  std::make_pair<OString, OString>("posv", OString::number(3)));
3387  break;
3388  case text::VertOrientation::CENTER:
3389  case text::VertOrientation::LINE_CENTER:
3390  m_aFlyProperties.push_back(
3391  std::make_pair<OString, OString>("posv", OString::number(2)));
3392  break;
3393  default:
3394  break;
3395  }
3396 
3397  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_SHPTOP);
3398  m_rExport.OutLong(rFlyVert.GetPos());
3399  if (m_pFlyFrameSize)
3400  {
3401  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_SHPBOTTOM);
3402  m_rExport.OutLong(rFlyVert.GetPos() + m_pFlyFrameSize->Height());
3403  }
3404 }
3405 
3407 {
3408  if (!(m_rExport.m_bOutFlyFrameAttrs && m_rExport.GetRTFFlySyntax()))
3409  return;
3410 
3411  switch (rFlyHori.GetRelationOrient())
3412  {
3413  case text::RelOrientation::PAGE_FRAME:
3414  m_aFlyProperties.push_back(
3415  std::make_pair<OString, OString>("posrelh", OString::number(1)));
3416  break;
3417  default:
3418  m_aFlyProperties.push_back(
3419  std::make_pair<OString, OString>("posrelh", OString::number(2)));
3420  m_rExport.Strm()
3421  .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_SHPBXCOLUMN)
3422  .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_SHPBXIGNORE);
3423  break;
3424  }
3425 
3426  switch (rFlyHori.GetHoriOrient())
3427  {
3428  case text::HoriOrientation::LEFT:
3429  m_aFlyProperties.push_back(
3430  std::make_pair<OString, OString>("posh", OString::number(1)));
3431  break;
3432  case text::HoriOrientation::CENTER:
3433  m_aFlyProperties.push_back(
3434  std::make_pair<OString, OString>("posh", OString::number(2)));
3435  break;
3436  case text::HoriOrientation::RIGHT:
3437  m_aFlyProperties.push_back(
3438  std::make_pair<OString, OString>("posh", OString::number(3)));
3439  break;
3440  default:
3441  break;
3442  }
3443 
3444  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_SHPLEFT);
3445  m_rExport.OutLong(rFlyHori.GetPos());
3446  if (m_pFlyFrameSize)
3447  {
3448  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_SHPRIGHT);
3449  m_rExport.OutLong(rFlyHori.GetPos() + m_pFlyFrameSize->Width());
3450  }
3451 }
3452 
3454 {
3455  if (m_rExport.GetRTFFlySyntax())
3456  return;
3457 
3458  RndStdIds eId = rAnchor.GetAnchorId();
3459  m_aRunText->append(OOO_STRING_SVTOOLS_RTF_FLYANCHOR);
3460  m_aRunText->append(static_cast<sal_Int32>(eId));
3461  switch (eId)
3462  {
3463  case RndStdIds::FLY_AT_PAGE:
3464  m_aRunText->append(OOO_STRING_SVTOOLS_RTF_FLYPAGE);
3465  m_aRunText->append(static_cast<sal_Int32>(rAnchor.GetPageNum()));
3466  break;
3467  case RndStdIds::FLY_AT_PARA:
3468  case RndStdIds::FLY_AS_CHAR:
3469  m_aRunText->append(OOO_STRING_SVTOOLS_RTF_FLYCNTNT);
3470  break;
3471  default:
3472  break;
3473  }
3474 }
3475 
3477 {
3478  if (m_rExport.GetRTFFlySyntax())
3479  {
3480  const Color& rColor = rBrush.GetColor();
3481  // We in fact need RGB to BGR, but the transformation is symmetric.
3482  m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3483  "fillColor", OString::number(wwUtility::RGBToBGR(rColor))));
3484  }
3485  else if (!rBrush.GetColor().IsTransparent())
3486  {
3487  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_CBPAT);
3488  m_aStyles.append(static_cast<sal_Int32>(m_rExport.GetColor(rBrush.GetColor())));
3489  }
3490 }
3491 
3493 {
3494  m_oFillStyle = rFillStyle.GetValue();
3495 }
3496 
3498 {
3499  if (*m_oFillStyle != drawing::FillStyle_GRADIENT)
3500  return;
3501 
3502  m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3503  "fillType", OString::number(7))); // Shade using the fillAngle
3504 
3505  const XGradient& rGradient = rFillGradient.GetGradientValue();
3506  const Color& rStartColor = rGradient.GetStartColor();
3507  m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3508  "fillBackColor", OString::number(wwUtility::RGBToBGR(rStartColor))));
3509 
3510  const Color& rEndColor = rGradient.GetEndColor();
3511  m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3512  "fillColor", OString::number(wwUtility::RGBToBGR(rEndColor))));
3513 
3514  switch (rGradient.GetGradientStyle())
3515  {
3516  case css::awt::GradientStyle_LINEAR:
3517  break;
3518  case css::awt::GradientStyle_AXIAL:
3519  m_aFlyProperties.push_back(
3520  std::make_pair<OString, OString>("fillFocus", OString::number(50)));
3521  break;
3522  case css::awt::GradientStyle_RADIAL:
3523  case css::awt::GradientStyle_ELLIPTICAL:
3524  case css::awt::GradientStyle_SQUARE:
3525  case css::awt::GradientStyle_RECT:
3526  default:
3527  break;
3528  }
3529 }
3530 
3532 {
3533  static const SvxBoxItemLine aBorders[] = { SvxBoxItemLine::TOP, SvxBoxItemLine::LEFT,
3534  SvxBoxItemLine::BOTTOM, SvxBoxItemLine::RIGHT };
3535  static const char* aBorderNames[]
3538 
3539  sal_uInt16 const nDist = rBox.GetSmallestDistance();
3540 
3541  if (m_rExport.GetRTFFlySyntax())
3542  {
3543  // Borders: spacing to contents, convert from twips to EMUs.
3544  m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3545  "dxTextLeft", OString::number(o3tl::convert(rBox.GetDistance(SvxBoxItemLine::LEFT),
3547  m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3548  "dyTextTop", OString::number(o3tl::convert(rBox.GetDistance(SvxBoxItemLine::TOP),
3550  m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3551  "dxTextRight", OString::number(o3tl::convert(rBox.GetDistance(SvxBoxItemLine::RIGHT),
3553  m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3554  "dyTextBottom", OString::number(o3tl::convert(rBox.GetDistance(SvxBoxItemLine::BOTTOM),
3556 
3557  const editeng::SvxBorderLine* pLeft = rBox.GetLine(SvxBoxItemLine::LEFT);
3558  const editeng::SvxBorderLine* pRight = rBox.GetLine(SvxBoxItemLine::RIGHT);
3559  const editeng::SvxBorderLine* pTop = rBox.GetLine(SvxBoxItemLine::TOP);
3560  const editeng::SvxBorderLine* pBottom = rBox.GetLine(SvxBoxItemLine::BOTTOM);
3561 
3562  if (!pLeft && !pRight && !pBottom && !pTop)
3563  {
3564  // fLine has default 'true', so need to write it out in case of no border.
3565  m_aFlyProperties.push_back(std::make_pair<OString, OString>("fLine", "0"));
3566  return;
3567  }
3568 
3569  // RTF has the flags fTopLine, fBottomLine, fLeftLine and fRightLine to disable single border
3570  // lines. But Word cannot disable single border lines. So we do not use them. In case of
3571  // single border lines it is better to draw all four borders than drawing none. So we look
3572  // whether a border line exists, which is effectively drawn.
3573  const editeng::SvxBorderLine* pBorder = nullptr;
3574  if (pTop && pTop->GetBorderLineStyle() != SvxBorderLineStyle::NONE)
3575  pBorder = pTop;
3576  else if (pBottom && pBottom->GetBorderLineStyle() != SvxBorderLineStyle::NONE)
3577  pBorder = pBottom;
3578  else if (pLeft && pLeft->GetBorderLineStyle() != SvxBorderLineStyle::NONE)
3579  pBorder = pLeft;
3580  else if (pRight && pRight->GetBorderLineStyle() != SvxBorderLineStyle::NONE)
3581  pBorder = pRight;
3582 
3583  if (!pBorder)
3584  {
3585  m_aFlyProperties.push_back(std::make_pair<OString, OString>("fLine", "0"));
3586  return;
3587  }
3588 
3589  const Color& rColor = pBorder->GetColor();
3590  // We in fact need RGB to BGR, but the transformation is symmetric.
3591  m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3592  "lineColor", OString::number(wwUtility::RGBToBGR(rColor))));
3593 
3594  double const fConverted(
3596  sal_Int32 nWidth = o3tl::convert(fConverted, o3tl::Length::twip, o3tl::Length::emu);
3597  m_aFlyProperties.push_back(
3598  std::make_pair<OString, OString>("lineWidth", OString::number(nWidth)));
3599 
3600  return;
3601  }
3602 
3603  if (rBox.GetTop() && rBox.GetBottom() && rBox.GetLeft() && rBox.GetRight()
3604  && *rBox.GetTop() == *rBox.GetBottom() && *rBox.GetTop() == *rBox.GetLeft()
3605  && *rBox.GetTop() == *rBox.GetRight() && nDist == rBox.GetDistance(SvxBoxItemLine::TOP)
3606  && nDist == rBox.GetDistance(SvxBoxItemLine::LEFT)
3607  && nDist == rBox.GetDistance(SvxBoxItemLine::BOTTOM)
3608  && nDist == rBox.GetDistance(SvxBoxItemLine::RIGHT))
3609  m_aSectionBreaks.append(
3610  OutBorderLine(m_rExport, rBox.GetTop(), OOO_STRING_SVTOOLS_RTF_BOX, nDist));
3611  else
3612  {
3613  SvxShadowLocation eShadowLocation = SvxShadowLocation::NONE;
3614  if (const SvxShadowItem* pItem = GetExport().HasItem(RES_SHADOW))
3615  eShadowLocation = pItem->GetLocation();
3616 
3617  const SvxBoxItemLine* pBrd = aBorders;
3618  const char** pBrdNms = aBorderNames;
3619  for (int i = 0; i < 4; ++i, ++pBrd, ++pBrdNms)
3620  {
3621  if (const editeng::SvxBorderLine* pLn = rBox.GetLine(*pBrd))
3622  {
3623  m_aSectionBreaks.append(OutBorderLine(m_rExport, pLn, *pBrdNms,
3624  rBox.GetDistance(*pBrd), eShadowLocation));
3625  }
3626  }
3627  }
3628 
3629  if (!m_bBufferSectionBreaks)
3630  m_aStyles.append(m_aSectionBreaks.makeStringAndClear());
3631 }
3632 
3633 void RtfAttributeOutput::FormatColumns_Impl(sal_uInt16 nCols, const SwFormatCol& rCol, bool bEven,
3634  SwTwips nPageSize)
3635 {
3636  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_COLS);
3637  m_rExport.OutLong(nCols);
3638 
3639  if (rCol.GetLineAdj() != COLADJ_NONE)
3640  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_LINEBETCOL);
3641 
3642  if (bEven)
3643  {
3644  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_COLSX);
3645  m_rExport.OutLong(rCol.GetGutterWidth(true));
3646  }
3647  else
3648  {
3649  const SwColumns& rColumns = rCol.GetColumns();
3650  for (sal_uInt16 n = 0; n < nCols;)
3651  {
3652  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_COLNO);
3653  m_rExport.OutLong(n + 1);
3654 
3655  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_COLW);
3656  m_rExport.OutLong(rCol.CalcPrtColWidth(n, nPageSize));
3657 
3658  if (++n != nCols)
3659  {
3660  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_COLSR);
3661  m_rExport.OutLong(rColumns[n - 1].GetRight() + rColumns[n].GetLeft());
3662  }
3663  }
3664  }
3665 }
3666 
3668 {
3669  if (rItem.GetValue())
3670  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_KEEPN);
3671 }
3672 
3674 {
3675  SAL_INFO("sw.rtf", "TODO: " << __func__);
3676 }
3677 
3679 {
3680  if (!rNumbering.IsCount())
3681  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_NOLINE);
3682 }
3683 
3685 {
3686  SvxFrameDirection nDir = rDirection.GetValue();
3687  if (nDir == SvxFrameDirection::Environment)
3688  nDir = GetExport().GetDefaultFrameDirection();
3689 
3690  if (m_rExport.m_bOutPageDescs)
3691  {
3692  if (nDir == SvxFrameDirection::Vertical_RL_TB)
3693  {
3694  m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_STEXTFLOW);
3695  m_aSectionBreaks.append(static_cast<sal_Int32>(1));
3696  if (!m_bBufferSectionBreaks)
3697  m_rExport.Strm().WriteOString(m_aSectionBreaks.makeStringAndClear());
3698  }
3699  return;
3700  }
3701 
3702  if (m_rExport.GetRTFFlySyntax())
3703  {
3704  if (nDir == SvxFrameDirection::Vertical_RL_TB)
3705  {
3706  // Top to bottom non-ASCII font
3707  m_aFlyProperties.push_back(std::make_pair<OString, OString>("txflTextFlow", "3"));
3708  }
3709  else if (rDirection.GetValue() == SvxFrameDirection::Vertical_LR_BT)
3710  {
3711  // Bottom to top non-ASCII font
3712  m_aFlyProperties.push_back(std::make_pair<OString, OString>("txflTextFlow", "2"));
3713  }
3714  return;
3715  }
3716 
3717  if (nDir == SvxFrameDirection::Horizontal_RL_TB)
3718  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_RTLPAR);
3719  else
3720  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_LTRPAR);
3721 }
3722 
3724 {
3725  const std::map<OUString, css::uno::Any>& rMap = rItem.GetGrabBag();
3726  for (const auto& rValue : rMap)
3727  {
3728  if (rValue.first == "ParaTopMarginBeforeAutoSpacing")
3729  {
3730  m_bParaBeforeAutoSpacing = true;
3731  rValue.second >>= m_nParaBeforeSpacing;
3732  m_nParaBeforeSpacing = o3tl::toTwips(m_nParaBeforeSpacing, o3tl::Length::mm100);
3733  }
3734  else if (rValue.first == "ParaBottomMarginAfterAutoSpacing")
3735  {
3736  m_bParaAfterAutoSpacing = true;
3737  rValue.second >>= m_nParaAfterSpacing;
3738  m_nParaAfterSpacing = o3tl::toTwips(m_nParaAfterSpacing, o3tl::Length::mm100);
3739  }
3740  }
3741 }
3742 
3744 
3746 
3748 {
3749  OUString sCmd; // for optional Parameters
3750  switch (pField->GetTyp()->Which())
3751  {
3752  //#i119803# Export user field for RTF filter
3753  case SwFieldIds::User:
3754  sCmd = pField->GetTyp()->GetName();
3755  m_rExport.OutputField(pField, ww::eNONE, sCmd);
3756  break;
3757  default:
3758  m_rExport.OutputField(pField, ww::eUNKNOWN, sCmd);
3759  break;
3760  }
3761 }
3762 
3763 void RtfAttributeOutput::RefField(const SwField& /*rField*/, const OUString& /*rRef*/)
3764 {
3765  SAL_INFO("sw.rtf", "TODO: " << __func__);
3766 }
3767 
3769 {
3770  SAL_INFO("sw.rtf", "TODO: " << __func__);
3771 }
3772 
3773 void RtfAttributeOutput::SetField(const SwField& /*rField*/, ww::eField /*eType*/,
3774  const OUString& /*rCmd*/)
3775 {
3776  SAL_INFO("sw.rtf", "TODO: " << __func__);
3777 }
3778 
3780 {
3781  const SwPostItField& rPField = *static_cast<const SwPostItField*>(pField);
3782 
3783  OString aName = OUStringToOString(rPField.GetName(), RTL_TEXTENCODING_UTF8);
3784  auto it = m_rOpenedAnnotationMarksIds.find(aName);
3785  if (it != m_rOpenedAnnotationMarksIds.end())
3786  {
3787  // In case this field is inside annotation marks, we want to write the
3788  // annotation itself after the annotation mark is closed, not here.
3789  m_aPostitFields[it->second] = &rPField;
3790  return;
3791  }
3792 
3793  m_aRunText->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_ATNID " ");
3794  m_aRunText->append(OUStringToOString(rPField.GetInitials(), m_rExport.GetCurrentEncoding()));
3795  m_aRunText->append("}");
3797  m_aRunText->append(OUStringToOString(rPField.GetPar1(), m_rExport.GetCurrentEncoding()));
3798  m_aRunText->append("}");
3799  m_aRunText->append(OOO_STRING_SVTOOLS_RTF_CHATN);
3800 
3802 
3803  if (m_nCurrentAnnotationMarkId != -1)
3804  {
3806  m_aRunText->append(m_nCurrentAnnotationMarkId);
3807  m_aRunText->append('}');
3808  }
3810  m_aRunText->append(static_cast<sal_Int32>(sw::ms::DateTime2DTTM(rPField.GetDateTime())));
3811  m_aRunText->append('}');
3812  if (const OutlinerParaObject* pObject = rPField.GetTextObject())
3813  m_rExport.SdrExporter().WriteOutliner(*pObject, TXT_ATN);
3814  m_aRunText->append('}');
3815 }
3816 
3818 {
3819  // this is handled in OutputFlyFrame_Impl()
3820  return true;
3821 }
3822 
3824 {
3825  m_aRunText->append("{" OOO_STRING_SVTOOLS_RTF_FIELD
3827  " MACROBUTTON None ");
3828  RunText(pField->GetPar1());
3829  m_aRunText->append("}}");
3830  return false; // do not expand
3831 }
3832 
3834  : AttributeOutputBase("") // ConvertURL isn't used now in RTF output
3835  , m_rExport(rExport)
3836  , m_pPrevPageDesc(nullptr)
3837  , m_nStyleId(0)
3838  , m_nListId(0)
3839  , m_bIsRTL(false)
3840  , m_nScript(i18n::ScriptType::LATIN)
3841  , m_bControlLtrRtl(false)
3842  , m_nNextAnnotationMarkId(0)
3843  , m_nCurrentAnnotationMarkId(-1)
3844  , m_bTableCellOpen(false)
3845  , m_nTableDepth(0)
3846  , m_bTableAfterCell(false)
3847  , m_nColBreakNeeded(false)
3848  , m_bBufferSectionBreaks(false)
3849  , m_bBufferSectionHeaders(false)
3850  , m_bLastTable(true)
3851  , m_bWroteCellInfo(false)
3852  , m_bTableRowEnded(false)
3853  , m_bIsBeforeFirstParagraph(true)
3854  , m_bSingleEmptyRun(false)
3855  , m_bInRun(false)
3856  , m_bInRuby(false)
3857  , m_pFlyFrameSize(nullptr)
3858  , m_bParaBeforeAutoSpacing(false)
3859  , m_nParaBeforeSpacing(0)
3860  , m_bParaAfterAutoSpacing(false)
3861  , m_nParaAfterSpacing(0)
3862 {
3863 }
3864 
3866 
3868 
3869 // These are used by wwFont::WriteRtf()
3870 
3872 void RtfAttributeOutput::StartFont(const OUString& rFamilyName) const
3873 {
3874  // write the font name hex-encoded, but without Unicode - Word at least
3875  // cannot read *both* Unicode and fallback as written by OutString
3877  msfilter::rtfutil::OutString(rFamilyName, m_rExport.GetCurrentEncoding(), false).getStr());
3878 }
3879 
3882 {
3883  m_rExport.Strm().WriteCharPtr(";}");
3885 }
3886 
3888 void RtfAttributeOutput::FontAlternateName(const OUString& rName) const
3889 {
3890  m_rExport.Strm()
3891  .WriteChar('{')
3894  .WriteChar(' ');
3895  // write the font name hex-encoded, but without Unicode - Word at least
3896  // cannot read *both* Unicode and fallback as written by OutString
3897  m_rExport.Strm()
3898  .WriteCharPtr(
3899  msfilter::rtfutil::OutString(rName, m_rExport.GetCurrentEncoding(), false).getStr())
3900  .WriteChar('}');
3901 }
3902 
3905 {
3907  m_rExport.OutULong(nCharSet);
3908  m_rExport.Strm().WriteChar(' ');
3909  m_rExport.SetCurrentEncoding(rtl_getTextEncodingFromWindowsCharset(nCharSet));
3910 }
3911 
3913 void RtfAttributeOutput::FontFamilyType(FontFamily eFamily, const wwFont& rFont) const
3914 {
3916 
3917  const char* pStr = OOO_STRING_SVTOOLS_RTF_FNIL;
3918  switch (eFamily)
3919  {
3920  case FAMILY_ROMAN:
3922  break;
3923  case FAMILY_SWISS:
3925  break;
3926  case FAMILY_MODERN:
3928  break;
3929  case FAMILY_SCRIPT:
3931  break;
3932  case FAMILY_DECORATIVE:
3934  break;
3935  default:
3936  break;
3937  }
3938  m_rExport.OutULong(m_rExport.m_aFontHelper.GetId(rFont)).WriteCharPtr(pStr);
3939 }
3940 
3943 {
3945 
3946  sal_uInt16 nVal = 0;
3947  switch (ePitch)
3948  {
3949  case PITCH_FIXED:
3950  nVal = 1;
3951  break;
3952  case PITCH_VARIABLE:
3953  nVal = 2;
3954  break;
3955  default:
3956  break;
3957  }
3958  m_rExport.OutULong(nVal);
3959 }
3960 
3961 static void lcl_AppendSP(OStringBuffer& rBuffer, const char cName[], const OUString& rValue,
3962  const RtfExport& rExport)
3963 {
3964  rBuffer.append("{" OOO_STRING_SVTOOLS_RTF_SP "{"); // "{\sp{"
3965  rBuffer.append(OOO_STRING_SVTOOLS_RTF_SN " "); //" \sn "
3966  rBuffer.append(cName); //"PropName"
3967  rBuffer.append("}{" OOO_STRING_SVTOOLS_RTF_SV " ");
3968  // "}{ \sv "
3969  rBuffer.append(msfilter::rtfutil::OutString(rValue, rExport.GetCurrentEncoding()));
3970  rBuffer.append("}}");
3971 }
3972 
3973 static OString ExportPICT(const SwFlyFrameFormat* pFlyFrameFormat, const Size& rOrig,
3974  const Size& rRendered, const Size& rMapped, const SwCropGrf& rCr,
3975  const char* pBLIPType, const sal_uInt8* pGraphicAry, sal_uInt64 nSize,
3976  const RtfExport& rExport, SvStream* pStream = nullptr,
3977  bool bWritePicProp = true, const SwAttrSet* pAttrSet = nullptr)
3978 {
3979  OStringBuffer aRet;
3980  if (pBLIPType && nSize && pGraphicAry)
3981  {
3982  bool bIsWMF = std::strcmp(pBLIPType, OOO_STRING_SVTOOLS_RTF_WMETAFILE) == 0;
3983 
3984  aRet.append("{" OOO_STRING_SVTOOLS_RTF_PICT);
3985 
3986  if (pFlyFrameFormat && bWritePicProp)
3987  {
3988  OUString sDescription = pFlyFrameFormat->GetObjDescription();
3989  //write picture properties - wzDescription at first
3990  //looks like: "{\*\picprop{\sp{\sn PropertyName}{\sv PropertyValue}}}"
3991  aRet.append(
3993  lcl_AppendSP(aRet, "wzDescription", sDescription, rExport);
3994  OUString sName = pFlyFrameFormat->GetObjTitle();
3995  lcl_AppendSP(aRet, "wzName", sName, rExport);
3996 
3997  if (pAttrSet)
3998  {
3999  MirrorGraph eMirror = pAttrSet->Get(RES_GRFATR_MIRRORGRF).GetValue();
4000  if (eMirror == MirrorGraph::Vertical || eMirror == MirrorGraph::Both)
4001  // Mirror on the vertical axis is a horizontal flip.
4002  lcl_AppendSP(aRet, "fFlipH", "1", rExport);
4003  }
4004 
4005  aRet.append("}"); //"}"
4006  }
4007 
4008  tools::Long nXCroppedSize = rOrig.Width() - (rCr.GetLeft() + rCr.GetRight());
4009  tools::Long nYCroppedSize = rOrig.Height() - (rCr.GetTop() + rCr.GetBottom());
4010  /* Graphic with a zero height or width, typically copied from webpages, caused crashes. */
4011  if (!nXCroppedSize)
4012  nXCroppedSize = 100;
4013  if (!nYCroppedSize)
4014  nYCroppedSize = 100;
4015 
4016  //Given the original size and taking cropping into account
4017  //first, how much has the original been scaled to get the
4018  //final rendered size
4019  aRet.append(OOO_STRING_SVTOOLS_RTF_PICSCALEX);
4020  aRet.append(static_cast<sal_Int32>((100 * rRendered.Width()) / nXCroppedSize));
4021  aRet.append(OOO_STRING_SVTOOLS_RTF_PICSCALEY);
4022  aRet.append(static_cast<sal_Int32>((100 * rRendered.Height()) / nYCroppedSize));
4023 
4024  aRet.append(OOO_STRING_SVTOOLS_RTF_PICCROPL);
4025  aRet.append(rCr.GetLeft());
4026  aRet.append(OOO_STRING_SVTOOLS_RTF_PICCROPR);
4027  aRet.append(rCr.GetRight());
4028  aRet.append(OOO_STRING_SVTOOLS_RTF_PICCROPT);
4029  aRet.append(rCr.GetTop());
4030  aRet.append(OOO_STRING_SVTOOLS_RTF_PICCROPB);
4031  aRet.append(rCr.GetBottom());
4032 
4033  aRet.append(OOO_STRING_SVTOOLS_RTF_PICW);
4034  aRet.append(static_cast<sal_Int32>(rMapped.Width()));
4035  aRet.append(OOO_STRING_SVTOOLS_RTF_PICH);
4036  aRet.append(static_cast<sal_Int32>(rMapped.Height()));
4037 
4038  aRet.append(OOO_STRING_SVTOOLS_RTF_PICWGOAL);
4039  aRet.append(static_cast<sal_Int32>(rOrig.Width()));
4040  aRet.append(OOO_STRING_SVTOOLS_RTF_PICHGOAL);
4041  aRet.append(static_cast<sal_Int32>(rOrig.Height()));
4042 
4043  aRet.append(pBLIPType);
4044  if (bIsWMF)
4045  {
4046  aRet.append(sal_Int32(8));
4047  msfilter::rtfutil::StripMetafileHeader(pGraphicAry, nSize);
4048  }
4049  aRet.append(SAL_NEWLINE_STRING);
4050  if (pStream)
4051  pStream->WriteOString(aRet.makeStringAndClear());
4052  if (pStream)
4053  msfilter::rtfutil::WriteHex(pGraphicAry, nSize, pStream);
4054  else
4055  aRet.append(msfilter::rtfutil::WriteHex(pGraphicAry, nSize));
4056  aRet.append('}');
4057  if (pStream)
4058  pStream->WriteOString(aRet.makeStringAndClear());
4059  }
4060  return aRet.makeStringAndClear();
4061 }
4062 
4064  SwOLENode& rOLENode, const Size& rSize)
4065 {
4067  Size aSize(rOLENode.GetTwipSize());
4068  Size aRendered(aSize);
4069  aRendered.setWidth(rSize.Width());
4070  aRendered.setHeight(rSize.Height());
4071  const Graphic* pGraphic = rOLENode.GetGraphic();
4072  Size aMapped(pGraphic->GetPrefSize());
4073  auto& rCr = rOLENode.GetAttr(RES_GRFATR_CROPGRF);
4074  const char* pBLIPType = OOO_STRING_SVTOOLS_RTF_PNGBLIP;
4075  const sal_uInt8* pGraphicAry = nullptr;
4076  SvMemoryStream aStream;
4077  if (GraphicConverter::Export(aStream, *pGraphic, ConvertDataFormat::PNG) != ERRCODE_NONE)
4078  SAL_WARN("sw.rtf", "failed to export the graphic");
4079  sal_uInt32 nSize = aStream.TellEnd();
4080  pGraphicAry = static_cast<sal_uInt8 const*>(aStream.GetData());
4081  m_aRunText->append(ExportPICT(pFlyFrameFormat, aSize, aRendered, aMapped, rCr, pBLIPType,
4082  pGraphicAry, nSize, m_rExport));
4083  m_aRunText->append("}"); // shppict
4086  SvMemoryStream aWmfStream;
4087  if (GraphicConverter::Export(aWmfStream, *pGraphic, ConvertDataFormat::WMF) != ERRCODE_NONE)
4088  SAL_WARN("sw.rtf", "failed to export the graphic");
4089  nSize = aWmfStream.TellEnd();
4090  pGraphicAry = static_cast<sal_uInt8 const*>(aWmfStream.GetData());
4091  m_aRunText->append(ExportPICT(pFlyFrameFormat, aSize, aRendered, aMapped, rCr, pBLIPType,
4092  pGraphicAry, nSize, m_rExport));
4093  m_aRunText->append("}"); // nonshppict
4094 }
4095 
4097  SwOLENode& rOLENode, const Size& rSize)
4098 {
4099  uno::Reference<embed::XEmbeddedObject> xObj(rOLENode.GetOLEObj().GetOleRef());
4100  sal_Int64 nAspect = rOLENode.GetAspect();
4101  svt::EmbeddedObjectRef aObjRef(xObj, nAspect);
4102  SvGlobalName aObjName(aObjRef->getClassID());
4103 
4104  if (!SotExchange::IsMath(aObjName))
4105  return false;
4106 
4108  uno::Reference<util::XCloseable> xClosable = xObj->getComponent();
4109  if (!xClosable.is())
4110  return false;
4111  // gcc4.4 (and 4.3 and possibly older) have a problem with dynamic_cast directly to the target class,
4112  // so help it with an intermediate cast. I'm not sure what exactly the problem is, seems to be unrelated
4113  // to RTLD_GLOBAL, so most probably a gcc bug.
4114  auto pBase
4115  = dynamic_cast<oox::FormulaExportBase*>(dynamic_cast<SfxBaseModel*>(xClosable.get()));
4116  assert(pBase != nullptr);
4117  OStringBuffer aBuf;
4118  if (pBase)
4119  pBase->writeFormulaRtf(aBuf, m_rExport.GetCurrentEncoding());
4120  m_aRunText->append(aBuf);
4121  // Replacement graphic.
4123  FlyFrameOLEReplacement(pFlyFrameFormat, rOLENode, rSize);
4124  m_aRunText->append("}"); // mmathPict
4125  m_aRunText->append("}"); // mmath
4126 
4127  return true;
4128 }
4129 
4130 void RtfAttributeOutput::FlyFrameOLE(const SwFlyFrameFormat* pFlyFrameFormat, SwOLENode& rOLENode,
4131  const Size& rSize)
4132 {
4133  if (FlyFrameOLEMath(pFlyFrameFormat, rOLENode, rSize))
4134  return;
4135 
4136  FlyFrameOLEReplacement(pFlyFrameFormat, rOLENode, rSize);
4137 }
4138 
4140  const SwGrfNode* pGrfNode)
4141 {
4142  SvMemoryStream aStream;
4143  const sal_uInt8* pGraphicAry = nullptr;
4144  sal_uInt32 nSize = 0;
4145 
4146  const Graphic& rGraphic(pGrfNode->GetGrf());
4147 
4148  // If there is no graphic there is not much point in parsing it
4149  if (rGraphic.GetType() == GraphicType::NONE)
4150  return;
4151 
4152  ConvertDataFormat aConvertDestinationFormat = ConvertDataFormat::WMF;
4153  const char* pConvertDestinationBLIPType = OOO_STRING_SVTOOLS_RTF_WMETAFILE;
4154 
4155  GfxLink aGraphicLink;
4156  const char* pBLIPType = nullptr;
4157  if (rGraphic.IsGfxLink())
4158  {
4159  aGraphicLink = rGraphic.GetGfxLink();
4160  nSize = aGraphicLink.GetDataSize();
4161  pGraphicAry = aGraphicLink.GetData();
4162  switch (aGraphicLink.GetType())
4163  {
4164  // #i15508# trying to add BMP type for better exports, need to check if this works
4165  // checked, does not work. Also need to reset pGraphicAry to NULL to force conversion
4166  // to PNG, else the BMP array will be used.
4167  // It may work using direct DIB data, but that needs to be checked eventually
4168  //
4169  // #i15508# before GfxLinkType::NativeBmp was added the graphic data
4170  // (to be hold in pGraphicAry) was not available; thus for now to stay
4171  // compatible, keep it that way by assigning NULL value to pGraphicAry
4172  case GfxLinkType::NativeBmp:
4173  // pBLIPType = OOO_STRING_SVTOOLS_RTF_WBITMAP;
4174  pGraphicAry = nullptr;
4175  break;
4176 
4177  case GfxLinkType::NativeJpg:
4178  pBLIPType = OOO_STRING_SVTOOLS_RTF_JPEGBLIP;
4179  break;
4180  case GfxLinkType::NativePng:
4181  pBLIPType = OOO_STRING_SVTOOLS_RTF_PNGBLIP;
4182  break;
4183  case GfxLinkType::NativeWmf:
4184  pBLIPType = aGraphicLink.IsEMF() ? OOO_STRING_SVTOOLS_RTF_EMFBLIP
4186  break;
4187  case GfxLinkType::NativeGif:
4188  // GIF is not supported by RTF, but we override default conversion to WMF, PNG seems fits better here.
4189  aConvertDestinationFormat = ConvertDataFormat::PNG;
4190  pConvertDestinationBLIPType = OOO_STRING_SVTOOLS_RTF_PNGBLIP;
4191  break;
4192  default:
4193  break;
4194  }
4195  }
4196 
4197  GraphicType eGraphicType = rGraphic.GetType();
4198  if (!pGraphicAry)
4199  {
4200  if (ERRCODE_NONE
4201  == GraphicConverter::Export(aStream, rGraphic,
4202  (eGraphicType == GraphicType::Bitmap)
4203  ? ConvertDataFormat::PNG
4204  : ConvertDataFormat::WMF))
4205  {
4206  pBLIPType = (eGraphicType == GraphicType::Bitmap) ? OOO_STRING_SVTOOLS_RTF_PNGBLIP
4208  nSize = aStream.TellEnd();
4209  pGraphicAry = static_cast<sal_uInt8 const*>(aStream.GetData());
4210  }
4211  }
4212 
4213  Size aMapped(eGraphicType == GraphicType::Bitmap ? rGraphic.GetSizePixel()
4214  : rGraphic.GetPrefSize());
4215 
4216  auto& rCr = pGrfNode->GetAttr(RES_GRFATR_CROPGRF);
4217 
4218  //Get original size in twips
4219  Size aSize(pGrfNode->GetTwipSize());
4220  Size aRendered(aSize);
4221 
4222  const SwFormatFrameSize& rS = pFlyFrameFormat->GetFrameSize();
4223  aRendered.setWidth(rS.GetWidth());
4224  aRendered.setHeight(rS.GetHeight());
4225 
4226  ww8::Frame* pFrame = nullptr;
4227  for (auto& rFrame : m_rExport.m_aFrames)
4228  {
4229  if (pFlyFrameFormat == &rFrame.GetFrameFormat())
4230  {
4231  pFrame = &rFrame;
4232  break;
4233  }
4234  }
4235 
4236  /*
4237  If the graphic is not of type WMF then we will have to store two
4238  graphics, one in the native format wrapped in shppict, and the other in
4239  the wmf format wrapped in nonshppict, so as to keep wordpad happy. If it's
4240  a wmf already then we don't need any such wrapping
4241  */
4242  bool bIsWMF = pBLIPType && std::strcmp(pBLIPType, OOO_STRING_SVTOOLS_RTF_WMETAFILE) == 0;
4243  const SwAttrSet* pAttrSet = pGrfNode->GetpSwAttrSet();
4244  if (!pFrame || pFrame->IsInline())
4245  {
4246  if (!bIsWMF)
4249  }
4250  else
4251  {
4255  m_pFlyFrameSize = &aRendered;
4256  m_rExport.m_pParentFrame = pFrame;
4258  m_rExport.SetRTFFlySyntax(true);
4259  m_rExport.OutputFormat(pFrame->GetFrameFormat(), false, false, true);
4261  m_rExport.SetRTFFlySyntax(false);
4262  m_rExport.m_pParentFrame = nullptr;
4263  m_pFlyFrameSize = nullptr;
4264  std::vector<std::pair<OString, OString>> aFlyProperties{
4265  { "shapeType", OString::number(ESCHER_ShpInst_PictureFrame) },
4266 
4267  { "wzDescription", msfilter::rtfutil::OutString(pFlyFrameFormat->GetObjDescription(),
4269  { "wzName", msfilter::rtfutil::OutString(pFlyFrameFormat->GetObjTitle(),
4271  };
4272 
4273  // If we have a wrap polygon, then handle that here.
4274  if (pFlyFrameFormat->GetSurround().IsContour())
4275  {
4276  if (const SwNoTextNode* pNd
4277  = sw::util::GetNoTextNodeFromSwFrameFormat(*pFlyFrameFormat))
4278  {
4279  const tools::PolyPolygon* pPolyPoly = pNd->HasContour();
4280  if (pPolyPoly && pPolyPoly->Count())
4281  {
4283  *pPolyPoly, pNd, /*bCorrectCrop=*/true);
4284  OStringBuffer aVerticies;
4285  for (sal_uInt16 i = 0; i < aPoly.GetSize(); ++i)
4286  aVerticies.append(";(" + OString::number(aPoly[i].X()) + ","
4287  + OString::number(aPoly[i].Y()) + ")");
4288  aFlyProperties.push_back(std::make_pair<OString, OString>(
4289  "pWrapPolygonVertices",
4290  "8;" + OString::number(aPoly.GetSize()) + aVerticies.makeStringAndClear()));
4291  }
4292  }
4293  }
4294 
4295  // Below text, behind document, opaque: they all refer to the same thing.
4296  if (!pFlyFrameFormat->GetOpaque().GetValue())
4297  aFlyProperties.push_back(std::make_pair<OString, OString>("fBehindDocument", "1"));
4298 
4299  if (pAttrSet)
4300  {
4301  if (Degree10 nRot10 = pAttrSet->Get(RES_GRFATR_ROTATION).GetValue())
4302  {
4303  // See writerfilter::rtftok::RTFSdrImport::applyProperty(),
4304  // positive rotation angles are clockwise in RTF, we have them
4305  // as counter-clockwise.
4306  // Additionally, RTF type is 0..360*2^16, our is 0..360*10.
4307  sal_Int32 nRot = nRot10.get() * -1 * RTF_MULTIPLIER / 10;
4308  aFlyProperties.emplace_back("rotation", OString::number(nRot));
4309  }
4310  }
4311 
4312  for (const std::pair<OString, OString>& rPair : aFlyProperties)
4313  {
4316  m_rExport.Strm().WriteOString(rPair.first);
4318  m_rExport.Strm().WriteOString(rPair.second);
4319  m_rExport.Strm().WriteCharPtr("}}");
4320  }
4322  " pib"
4323  "}{" OOO_STRING_SVTOOLS_RTF_SV " ");
4324  }
4325 
4326  bool bWritePicProp = !pFrame || pFrame->IsInline();
4327  if (pBLIPType)
4328  ExportPICT(pFlyFrameFormat, aSize, aRendered, aMapped, rCr, pBLIPType, pGraphicAry, nSize,
4329  m_rExport, &m_rExport.Strm(), bWritePicProp, pAttrSet);
4330  else
4331  {
4332  aStream.Seek(0);
4333  if (GraphicConverter::Export(aStream, rGraphic, aConvertDestinationFormat) != ERRCODE_NONE)
4334  SAL_WARN("sw.rtf", "failed to export the graphic");
4335  pBLIPType = pConvertDestinationBLIPType;
4336  nSize = aStream.TellEnd();
4337  pGraphicAry = static_cast<sal_uInt8 const*>(aStream.GetData());
4338 
4339  ExportPICT(pFlyFrameFormat, aSize, aRendered, aMapped, rCr, pBLIPType, pGraphicAry, nSize,
4340  m_rExport, &m_rExport.Strm(), bWritePicProp, pAttrSet);
4341  }
4342 
4343  if (!pFrame || pFrame->IsInline())
4344  {
4345  if (!bIsWMF)
4346  {
4349 
4350  aStream.Seek(0);
4351  if (GraphicConverter::Export(aStream, rGraphic, ConvertDataFormat::WMF) != ERRCODE_NONE)
4352  SAL_WARN("sw.rtf", "failed to export the graphic");
4354  nSize = aStream.TellEnd();
4355  pGraphicAry = static_cast<sal_uInt8 const*>(aStream.GetData());
4356 
4357  ExportPICT(pFlyFrameFormat, aSize, aRendered, aMapped, rCr, pBLIPType, pGraphicAry,
4358  nSize, m_rExport, &m_rExport.Strm());
4359 
4360  m_rExport.Strm().WriteChar('}');
4361  }
4362  }
4363  else
4364  m_rExport.Strm().WriteCharPtr("}}}}"); // Close SV, SP, SHPINST and SHP.
4365 
4367 }
4368 
4369 void RtfAttributeOutput::BulletDefinition(int /*nId*/, const Graphic& rGraphic, Size aSize)
4370 {
4373 
4375  m_rExport.OutULong(aSize.Width());
4377  m_rExport.OutULong(aSize.Height());
4378 
4380  const sal_uInt8* pGraphicAry = nullptr;
4381  SvMemoryStream aStream;
4382  if (GraphicConverter::Export(aStream, rGraphic, ConvertDataFormat::PNG) != ERRCODE_NONE)
4383  SAL_WARN("sw.rtf", "failed to export the numbering picture bullet");
4384  sal_uInt32 nSize = aStream.TellEnd();
4385  pGraphicAry = static_cast<sal_uInt8 const*>(aStream.GetData());
4386  msfilter::rtfutil::WriteHex(pGraphicAry, nSize, &m_rExport.Strm());
4387  m_rExport.Strm().WriteCharPtr("}}"); // pict, shppict
4388 }
4389 
4391 {
4392  if (!rRtlGutter.GetValue())
4393  {
4394  return;
4395  }
4396 
4398 }
4399 
4401 {
4402  // Text wrapping break of type:
4404  m_aStyles.append(static_cast<sal_Int32>(rLineBreak.GetEnumValue()));
4405 
4406  // Write the linebreak itself.
4407  RunText("\x0b");
4408 }
4409 
4410 /* 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:139
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
SwNodeOffset EndOfSectionIndex() const
Definition: node.hxx:687
#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
const T * GetItemIfSet(TypedWhichId< T > nWhich, bool bSrchInParent=true) const
#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:164
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:115
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:178
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:96
#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:128
#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:291
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:939
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:92
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_POSTUR