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  const OString aProperties = MoveCharacterProperties(true);
388  m_rExport.Strm().WriteOString(aProperties);
389 }
390 
391 void RtfAttributeOutput::StartRun(const SwRedlineData* pRedlineData, sal_Int32 /*nPos*/,
392  bool bSingleEmptyRun)
393 {
394  SAL_INFO("sw.rtf", __func__ << ", bSingleEmptyRun: " << bSingleEmptyRun);
395 
396  m_bInRun = true;
397  m_bSingleEmptyRun = bSingleEmptyRun;
398  if (!m_bSingleEmptyRun)
399  m_aRun->append('{');
400 
401  // if there is some redlining in the document, output it
402  Redline(pRedlineData);
403 
404  OSL_ENSURE(m_aRunText.getLength() == 0, "m_aRunText is not empty");
405 }
406 
407 void RtfAttributeOutput::EndRun(const SwTextNode* /*pNode*/, sal_Int32 /*nPos*/, bool /*bLastRun*/)
408 {
409  m_aRun->append(SAL_NEWLINE_STRING);
410  m_aRun.appendAndClear(m_aRunText);
411 
412  if (m_bInRuby)
413  {
414  m_aRun->append(")}}{" OOO_STRING_SVTOOLS_RTF_FLDRSLT " {}}}");
415  m_bInRuby = false;
416  }
417 
418  if (!m_bSingleEmptyRun && m_bInRun)
419  m_aRun->append('}');
420  m_bInRun = false;
421 }
422 
424 {
425  OSL_ENSURE(m_aStyles.getLength() == 0, "m_aStyles is not empty");
426 }
427 
429 {
430  const OString aProperties = MoveCharacterProperties(true);
431  m_aRun->append(aProperties.getStr());
432 }
433 
434 OString RtfAttributeOutput::MoveCharacterProperties(bool aAutoWriteRtlLtr)
435 {
436  const OString aAssocHich = m_aStylesAssocHich.makeStringAndClear();
437  const OString aAssocDbch = m_aStylesAssocDbch.makeStringAndClear();
438  const OString aAssocRtlch = m_aStylesAssocRtlch.makeStringAndClear();
439  const OString aAssocLtrch = m_aStylesAssocLtrch.makeStringAndClear();
440  const OString aNormal = m_aStyles.makeStringAndClear();
441  OStringBuffer aBuf;
442 
443  if (aAutoWriteRtlLtr && !m_bControlLtrRtl)
444  {
445  m_bControlLtrRtl = !aAssocRtlch.isEmpty();
446  m_bIsRTL = false;
447  m_nScript = i18n::ScriptType::LATIN;
448  }
449 
450  if (m_bIsRTL)
451  {
452  if (!aAssocRtlch.isEmpty())
453  {
454  aBuf.append(OOO_STRING_SVTOOLS_RTF_LTRCH + aAssocLtrch
455  + " " OOO_STRING_SVTOOLS_RTF_RTLCH + aAssocRtlch);
456  }
457  }
458  else
459  {
460  if (!aAssocRtlch.isEmpty())
461  {
462  aBuf.append(OOO_STRING_SVTOOLS_RTF_RTLCH + aAssocRtlch
463  + " " OOO_STRING_SVTOOLS_RTF_LTRCH + aAssocLtrch);
464  }
465  if (!aAssocHich.isEmpty())
466  {
467  aBuf.append(OOO_STRING_SVTOOLS_RTF_HICH + aAssocHich);
468  }
469  if (!aNormal.isEmpty())
470  {
471  aBuf.append(OOO_STRING_SVTOOLS_RTF_LOCH + aNormal);
472  }
473  if (!aAssocDbch.isEmpty())
474  {
475  aBuf.append(OOO_STRING_SVTOOLS_RTF_DBCH + aAssocDbch);
476  }
477  }
478 
479  if (m_bControlLtrRtl)
480  {
481  m_bControlLtrRtl = false;
482 
483  switch (m_nScript)
484  {
485  case i18n::ScriptType::LATIN:
486  aBuf.append(OOO_STRING_SVTOOLS_RTF_LOCH);
487  break;
488  case i18n::ScriptType::ASIAN:
489  aBuf.append(OOO_STRING_SVTOOLS_RTF_DBCH);
490  break;
491  case i18n::ScriptType::COMPLEX:
492  /* noop */
493  default:
494  /* should not happen? */
495  break;
496  }
497  }
498 
499  return aBuf.makeStringAndClear();
500 }
501 
502 void RtfAttributeOutput::RunText(const OUString& rText, rtl_TextEncoding /*eCharSet*/)
503 {
504  SAL_INFO("sw.rtf", __func__ << ", rText: " << rText);
505  RawText(rText, m_rExport.GetCurrentEncoding());
506 }
507 
508 OStringBuffer& RtfAttributeOutput::RunText() { return m_aRunText.getLastBuffer(); }
509 
510 void RtfAttributeOutput::RawText(const OUString& rText, rtl_TextEncoding eCharSet)
511 {
512  m_aRunText->append(msfilter::rtfutil::OutString(rText, eCharSet));
513 }
514 
515 void RtfAttributeOutput::StartRuby(const SwTextNode& rNode, sal_Int32 /*nPos*/,
516  const SwFormatRuby& rRuby)
517 {
518  WW8Ruby aWW8Ruby(rNode, rRuby, GetExport());
519  OUString aStr(FieldString(ww::eEQ) + "\\* jc");
520  aStr += OUString::number(aWW8Ruby.GetJC()) + " \\* \"Font:" + aWW8Ruby.GetFontFamily()
521  + "\" \\* hps";
522  aStr += OUString::number((aWW8Ruby.GetRubyHeight() + 5) / 10) + " \\o";
523  if (aWW8Ruby.GetDirective())
524  {
525  aStr += "\\a" + OUStringChar(aWW8Ruby.GetDirective());
526  }
527  aStr += "(\\s\\up " + OUString::number((aWW8Ruby.GetBaseHeight() + 10) / 20 - 1) + "(";
528  m_rExport.OutputField(nullptr, ww::eEQ, aStr, FieldFlags::Start | FieldFlags::CmdStart);
529  aStr = rRuby.GetText() + "),";
530  m_rExport.OutputField(nullptr, ww::eEQ, aStr, FieldFlags::NONE);
531  m_bInRuby = true;
532 }
533 
534 void RtfAttributeOutput::EndRuby(const SwTextNode& /*rNode*/, sal_Int32 /*nPos*/) {}
535 
536 bool RtfAttributeOutput::StartURL(const OUString& rUrl, const OUString& rTarget)
537 {
538  m_aURLs.push(rUrl);
539  // Ignore hyperlink without a URL.
540  if (!rUrl.isEmpty())
541  {
542  m_aRun->append('{');
543  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FIELD);
544  m_aRun->append('{');
545  m_aRun->append(OOO_STRING_SVTOOLS_RTF_IGNORE);
546  m_aRun->append(OOO_STRING_SVTOOLS_RTF_FLDINST);
547  m_aRun->append(" HYPERLINK ");
548 
549  m_aRun->append("\"");
550  m_aRun->append(msfilter::rtfutil::OutString(rUrl, m_rExport.GetCurrentEncoding()));
551  m_aRun->append("\" ");
552 
553  if (!rTarget.isEmpty())
554  {
555  m_aRun->append("\\\\t \"");
556  m_aRun->append(msfilter::rtfutil::OutString(rTarget, m_rExport.GetCurrentEncoding()));
557  m_aRun->append("\" ");
558  }
559 
560  m_aRun->append("}");
561  m_aRun->append("{" OOO_STRING_SVTOOLS_RTF_FLDRSLT " {");
562  }
563  return true;
564 }
565 
566 bool RtfAttributeOutput::EndURL(bool const isAtEndOfParagraph)
567 {
568  if (m_aURLs.empty())
569  {
570  return true;
571  }
572 
573  const OUString& rURL = m_aURLs.top();
574  if (!rURL.isEmpty())
575  {
576  // UGLY: usually EndRun is called earlier, but there is an extra
577  // call to OutAttrWithRange() when at the end of the paragraph,
578  // so in that special case the output needs to be appended to the
579  // new run's text instead of the previous run
580  if (isAtEndOfParagraph)
581  {
582  // close the fldrslt group
583  m_aRunText->append("}}");
584  // close the field group
585  m_aRunText->append('}');
586  }
587  else
588  {
589  // close the fldrslt group
590  m_aRun->append("}}");
591  // close the field group
592  m_aRun->append('}');
593  }
594  }
595  m_aURLs.pop();
596  return true;
597 }
598 
599 void RtfAttributeOutput::FieldVanish(const OUString& /*rText*/, ww::eField /*eType*/,
600  OUString const* /*pBookmarkName*/)
601 {
602  SAL_INFO("sw.rtf", "TODO: " << __func__);
603 }
604 
606 {
607  if (!pRedline)
608  return;
609 
610  if (pRedline->GetType() == RedlineType::Insert)
611  {
612  m_aRun->append(OOO_STRING_SVTOOLS_RTF_REVISED);
613  m_aRun->append(OOO_STRING_SVTOOLS_RTF_REVAUTH);
614  m_aRun->append(static_cast<sal_Int32>(
615  m_rExport.GetRedline(SW_MOD()->GetRedlineAuthor(pRedline->GetAuthor()))));
616  m_aRun->append(OOO_STRING_SVTOOLS_RTF_REVDTTM);
617  }
618  else if (pRedline->GetType() == RedlineType::Delete)
619  {
620  m_aRun->append(OOO_STRING_SVTOOLS_RTF_DELETED);
621  m_aRun->append(OOO_STRING_SVTOOLS_RTF_REVAUTHDEL);
622  m_aRun->append(static_cast<sal_Int32>(
623  m_rExport.GetRedline(SW_MOD()->GetRedlineAuthor(pRedline->GetAuthor()))));
624  m_aRun->append(OOO_STRING_SVTOOLS_RTF_REVDTTMDEL);
625  }
626  m_aRun->append(static_cast<sal_Int32>(sw::ms::DateTime2DTTM(pRedline->GetTimeStamp())));
627  m_aRun->append(' ');
628 }
629 
631  const SwFormatDrop& /*rSwFormatDrop*/, sal_uInt16 /*nStyle*/,
632  ww8::WW8TableNodeInfo::Pointer_t /*pTextNodeInfo*/,
633  ww8::WW8TableNodeInfoInner::Pointer_t /*pTextNodeInfoInner*/)
634 {
635  SAL_INFO("sw.rtf", "TODO: " << __func__);
636 }
637 
638 void RtfAttributeOutput::ParagraphStyle(sal_uInt16 nStyle)
639 {
640  OString* pStyle = m_rExport.GetStyle(nStyle);
641  OStringBuffer aStyle;
642  aStyle.append(OOO_STRING_SVTOOLS_RTF_S);
643  aStyle.append(static_cast<sal_Int32>(nStyle));
644  if (pStyle)
645  aStyle.append(pStyle->getStr());
646  if (!m_bBufferSectionHeaders)
647  m_rExport.Strm().WriteOString(aStyle.makeStringAndClear());
648  else
649  m_aSectionHeaders.append(aStyle);
650 }
651 
653  ww8::WW8TableNodeInfoInner::Pointer_t /*pTableTextNodeInfoInner*/)
654 {
655  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_INTBL);
656  if (m_nTableDepth > 1)
657  {
658  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ITAP);
659  m_aStyles.append(static_cast<sal_Int32>(m_nTableDepth));
660  }
661  m_bWroteCellInfo = true;
662 }
663 
665 {
666  /* noop */
667 }
668 
670  ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)
671 {
672  InitTableHelper(pTableTextNodeInfoInner);
673 
674  const SwTable* pTable = pTableTextNodeInfoInner->getTable();
675  SwFrameFormat* pFormat = pTable->GetFrameFormat();
676 
677  m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_TROWD);
678  TableOrientation(pTableTextNodeInfoInner);
679  TableBidi(pTableTextNodeInfoInner);
680  TableHeight(pTableTextNodeInfoInner);
681  TableCanSplit(pTableTextNodeInfoInner);
682 
683  // Cell margins
684  const SvxBoxItem& rBox = pFormat->GetBox();
685  static const SvxBoxItemLine aBorders[] = { SvxBoxItemLine::TOP, SvxBoxItemLine::LEFT,
686  SvxBoxItemLine::BOTTOM, SvxBoxItemLine::RIGHT };
687 
688  static const char* aRowPadNames[]
691 
692  static const char* aRowPadUnits[]
695 
696  for (int i = 0; i < 4; ++i)
697  {
698  m_aRowDefs.append(aRowPadUnits[i]);
699  m_aRowDefs.append(sal_Int32(3));
700  m_aRowDefs.append(aRowPadNames[i]);
701  m_aRowDefs.append(static_cast<sal_Int32>(rBox.GetDistance(aBorders[i])));
702  }
703 
704  // The cell-dependent properties
705  const double fWidthRatio = m_pTableWrt->GetAbsWidthRatio();
706  const SwWriteTableRows& aRows = m_pTableWrt->GetRows();
707  SwWriteTableRow* pRow = aRows[pTableTextNodeInfoInner->getRow()].get();
708  SwTwips nSz = 0;
709 
710  // Not using m_nTableDepth, which is not yet incremented here.
711  sal_uInt32 nCurrentDepth = pTableTextNodeInfoInner->getDepth();
712  m_aCells[nCurrentDepth] = pRow->GetCells().size();
713  for (sal_uInt32 i = 0; i < m_aCells[nCurrentDepth]; i++)
714  {
715  const SwWriteTableCell* const pCell = pRow->GetCells()[i].get();
716  const SwFrameFormat* pCellFormat = pCell->GetBox()->GetFrameFormat();
717 
718  pTableTextNodeInfoInner->setCell(i);
719  TableCellProperties(pTableTextNodeInfoInner);
720 
721  // Right boundary: this can't be in TableCellProperties as the old
722  // value of nSz is needed.
723  nSz += pCellFormat->GetFrameSize().GetWidth();
724  m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CELLX);
725  m_aRowDefs.append(static_cast<sal_Int32>(pFormat->GetLRSpace().GetLeft()
726  + rtl::math::round(nSz * fWidthRatio)));
727  }
728 }
729 
731  ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)
732 {
733  /*
734  * The function name is a bit misleading: given that we write borders
735  * before each row, we just have borders, not default ones. Additionally,
736  * this function actually writes borders for a specific cell only and is
737  * called for each cell.
738  */
739 
740  const SwWriteTableRows& aRows = m_pTableWrt->GetRows();
741  SwWriteTableRow* pRow = aRows[pTableTextNodeInfoInner->getRow()].get();
742  const SwWriteTableCell* const pCell
743  = pRow->GetCells()[pTableTextNodeInfoInner->getCell()].get();
744  const SwFrameFormat* pCellFormat = pCell->GetBox()->GetFrameFormat();
745  const SfxPoolItem* pItem;
746  if (!pCellFormat->GetAttrSet().HasItem(RES_BOX, &pItem))
747  return;
748 
749  auto& rBox = pItem->StaticWhichCast(RES_BOX);
750  static const SvxBoxItemLine aBorders[] = { SvxBoxItemLine::TOP, SvxBoxItemLine::LEFT,
751  SvxBoxItemLine::BOTTOM, SvxBoxItemLine::RIGHT };
752  static const char* aBorderNames[]
755  //Yes left and top are swapped with each other for cell padding! Because
756  //that's what the thundering annoying rtf export/import word xp does.
757  static const char* aCellPadNames[]
760  static const char* aCellPadUnits[]
763  for (int i = 0; i < 4; ++i)
764  {
765  if (const editeng::SvxBorderLine* pLn = rBox.GetLine(aBorders[i]))
766  m_aRowDefs.append(OutTBLBorderLine(m_rExport, pLn, aBorderNames[i]));
767  if (rBox.GetDistance(aBorders[i]))
768  {
769  m_aRowDefs.append(aCellPadUnits[i]);
770  m_aRowDefs.append(sal_Int32(3));
771  m_aRowDefs.append(aCellPadNames[i]);
772  m_aRowDefs.append(static_cast<sal_Int32>(rBox.GetDistance(aBorders[i])));
773  }
774  }
775 }
776 
778  ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)
779 {
780  const SwTable* pTable = pTableTextNodeInfoInner->getTable();
781  const SwTableBox* pTableBox = pTableTextNodeInfoInner->getTableBox();
782  const SwTableLine* pTableLine = pTableBox->GetUpper();
783 
784  Color aColor = COL_AUTO;
785  auto pTableColorProp
787  if (pTableColorProp)
788  aColor = pTableColorProp->GetColor();
789 
790  auto pRowColorProp
792  if (pRowColorProp && pRowColorProp->GetColor() != COL_AUTO)
793  aColor = pRowColorProp->GetColor();
794 
795  const SwWriteTableRows& aRows = m_pTableWrt->GetRows();
796  SwWriteTableRow* pRow = aRows[pTableTextNodeInfoInner->getRow()].get();
797  const SwWriteTableCell* const pCell
798  = pRow->GetCells()[pTableTextNodeInfoInner->getCell()].get();
799  const SwFrameFormat* pCellFormat = pCell->GetBox()->GetFrameFormat();
800  const SfxPoolItem* pItem;
801  if (pCellFormat->GetAttrSet().HasItem(RES_BACKGROUND, &pItem))
802  {
803  auto& rBack = pItem->StaticWhichCast(RES_BACKGROUND);
804  if (rBack.GetColor() != COL_AUTO)
805  aColor = rBack.GetColor();
806  }
807 
808  if (!aColor.IsTransparent())
809  {
810  m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CLCBPAT);
811  m_aRowDefs.append(static_cast<sal_Int32>(m_rExport.GetColor(aColor)));
812  }
813 }
814 
816  ww8::WW8TableNodeInfoInner::Pointer_t /*pTableTextNodeInfoInner*/)
817 {
818 }
819 
821  ww8::WW8TableNodeInfoInner::Pointer_t /*pTableTextNodeInfoInner*/)
822 {
823 }
824 
826 {
827  const SwTableBox* pTabBox = pTableTextNodeInfoInner->getTableBox();
828  const SwTableLine* pTabLine = pTabBox->GetUpper();
829  const SwFrameFormat* pLineFormat = pTabLine->GetFrameFormat();
830  const SwFormatFrameSize& rLSz = pLineFormat->GetFrameSize();
831 
832  if (!(SwFrameSize::Variable != rLSz.GetHeightSizeType() && rLSz.GetHeight()))
833  return;
834 
835  sal_Int32 nHeight = 0;
836 
837  switch (rLSz.GetHeightSizeType())
838  {
839  case SwFrameSize::Fixed:
840  nHeight = -rLSz.GetHeight();
841  break;
843  nHeight = rLSz.GetHeight();
844  break;
845  default:
846  break;
847  }
848 
849  if (nHeight)
850  {
851  m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_TRRH);
852  m_aRowDefs.append(nHeight);
853  }
854 }
855 
857  ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)
858 {
859  const SwTableBox* pTabBox = pTableTextNodeInfoInner->getTableBox();
860  const SwTableLine* pTabLine = pTabBox->GetUpper();
861  const SwFrameFormat* pLineFormat = pTabLine->GetFrameFormat();
862  const SwFormatRowSplit& rSplittable = pLineFormat->GetRowSplit();
863 
864  // The rtf default is to allow a row to break
865  if (!rSplittable.GetValue())
866  m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_TRKEEP);
867 }
868 
870 {
871  const SwTable* pTable = pTableTextNodeInfoInner->getTable();
872  const SwFrameFormat* pFrameFormat = pTable->GetFrameFormat();
873 
874  if (m_rExport.TrueFrameDirection(*pFrameFormat) != SvxFrameDirection::Horizontal_RL_TB)
875  m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_LTRROW);
876  else
877  m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_RTLROW);
878 }
879 
881  ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)
882 {
883  const SwWriteTableRows& aRows = m_pTableWrt->GetRows();
884  SwWriteTableRow* pRow = aRows[pTableTextNodeInfoInner->getRow()].get();
885  const SwWriteTableCell* const pCell
886  = pRow->GetCells()[pTableTextNodeInfoInner->getCell()].get();
887  const SwFrameFormat* pCellFormat = pCell->GetBox()->GetFrameFormat();
888 
889  // Text direction.
890  if (SvxFrameDirection::Vertical_RL_TB == m_rExport.TrueFrameDirection(*pCellFormat))
891  m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CLTXTBRL);
892  else if (SvxFrameDirection::Vertical_LR_BT == m_rExport.TrueFrameDirection(*pCellFormat))
893  m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CLTXBTLR);
894 
895  const SfxPoolItem* pItem;
896 
897  // vertical merges
898  if (pCell->GetRowSpan() > 1)
899  m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CLVMGF);
900  else if (pCell->GetRowSpan() == 0)
901  m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CLVMRG);
902 
903  // vertical alignment
904  if (!pCellFormat->GetAttrSet().HasItem(RES_VERT_ORIENT, &pItem))
905  return;
906 
907  switch (pItem->StaticWhichCast(RES_VERT_ORIENT).GetVertOrient())
908  {
909  case text::VertOrientation::CENTER:
910  m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CLVERTALC);
911  break;
912  case text::VertOrientation::BOTTOM:
913  m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CLVERTALB);
914  break;
915  default:
916  m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CLVERTALT);
917  break;
918  }
919 }
920 
922 {
923  // This is called when the nested table ends in a cell, and there's no
924  // paragraph behind that; so we must check for the ends of cell, rows,
925  // and tables
926  FinishTableRowCell(pNodeInfoInner);
927 }
928 
930  ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)
931 {
932  const SwTable* pTable = pTableTextNodeInfoInner->getTable();
933  SwFrameFormat* pFormat = pTable->GetFrameFormat();
934 
935  OStringBuffer aTableAdjust(OOO_STRING_SVTOOLS_RTF_TRQL);
936  switch (pFormat->GetHoriOrient().GetHoriOrient())
937  {
938  case text::HoriOrientation::CENTER:
939  aTableAdjust.setLength(0);
940  aTableAdjust.append(OOO_STRING_SVTOOLS_RTF_TRQC);
941  break;
942  case text::HoriOrientation::RIGHT:
943  aTableAdjust.setLength(0);
944  aTableAdjust.append(OOO_STRING_SVTOOLS_RTF_TRQR);
945  break;
947  case text::HoriOrientation::LEFT_AND_WIDTH:
948  aTableAdjust.append(OOO_STRING_SVTOOLS_RTF_TRLEFT);
949  aTableAdjust.append(static_cast<sal_Int32>(pFormat->GetLRSpace().GetLeft()));
950  break;
951  default:
952  break;
953  }
954 
955  m_aRowDefs.append(aTableAdjust);
956 }
957 
959  ww8::WW8TableNodeInfoInner::Pointer_t /*pTableTextNodeInfoInner*/)
960 {
961  SAL_INFO("sw.rtf", "TODO: " << __func__);
962 }
963 
964 void RtfAttributeOutput::TableRowEnd(sal_uInt32 /*nDepth*/) { /* noop, see EndTableRow() */}
965 
966 /*
967  * Our private table methods.
968  */
969 
971  const ww8::WW8TableNodeInfoInner::Pointer_t& pTableTextNodeInfoInner)
972 {
973  const SwTable* pTable = pTableTextNodeInfoInner->getTable();
974  if (m_pTableWrt && pTable == m_pTableWrt->GetTable())
975  return;
976 
977  tools::Long nPageSize = 0;
978  bool bRelBoxSize = false;
979 
980  // Create the SwWriteTable instance to use col spans
981  GetTablePageSize(pTableTextNodeInfoInner.get(), nPageSize, bRelBoxSize);
982 
983  const SwFrameFormat* pFormat = pTable->GetFrameFormat();
984  const sal_uInt32 nTableSz = pFormat->GetFrameSize().GetWidth();
985 
986  const SwHTMLTableLayout* pLayout = pTable->GetHTMLTableLayout();
987  if (pLayout && pLayout->IsExportable())
988  m_pTableWrt = std::make_unique<SwWriteTable>(pTable, pLayout);
989  else
990  m_pTableWrt = std::make_unique<SwWriteTable>(pTable, pTable->GetTabLines(), nPageSize,
991  nTableSz, false);
992 }
993 
995 {
996  // To trigger calling InitTableHelper()
997  m_pTableWrt.reset();
998 }
999 
1001  const ww8::WW8TableNodeInfoInner::Pointer_t& pTableTextNodeInfoInner)
1002 {
1003  sal_uInt32 nCurrentDepth = pTableTextNodeInfoInner->getDepth();
1004  SAL_INFO("sw.rtf", __func__ << ", (depth is " << nCurrentDepth << ")");
1005  m_bTableRowEnded = false;
1006 
1007  TableDefinition(pTableTextNodeInfoInner);
1008 
1009  if (!m_bLastTable)
1010  m_aTables.push_back(m_aRowDefs.makeStringAndClear());
1011 
1012  // We'll write the table definition for nested tables later
1013  if (nCurrentDepth > 1)
1014  return;
1015  // Empty the previous row closing buffer before starting the new one,
1016  // necessary for subtables.
1017  m_rExport.Strm().WriteOString(m_aAfterRuns.makeStringAndClear());
1018  m_rExport.Strm().WriteOString(m_aRowDefs.makeStringAndClear());
1019 }
1020 
1021 void RtfAttributeOutput::StartTableCell() { m_bTableCellOpen = true; }
1022 
1024  const ww8::WW8TableNodeInfoInner::Pointer_t& pTableTextNodeInfoInner)
1025 {
1026  TableDefaultBorders(pTableTextNodeInfoInner);
1027  TableBackgrounds(pTableTextNodeInfoInner);
1028  TableVerticalCell(pTableTextNodeInfoInner);
1029 }
1030 
1032 {
1033  SAL_INFO("sw.rtf", __func__ << ", (depth is " << m_nTableDepth << ")");
1034 
1035  if (!m_bWroteCellInfo)
1036  {
1037  m_aAfterRuns.append(OOO_STRING_SVTOOLS_RTF_INTBL);
1038  m_aAfterRuns.append(OOO_STRING_SVTOOLS_RTF_ITAP);
1039  m_aAfterRuns.append(static_cast<sal_Int32>(m_nTableDepth));
1040  }
1041  if (m_nTableDepth > 1)
1042  m_aAfterRuns.append(OOO_STRING_SVTOOLS_RTF_NESTCELL);
1043  else
1044  m_aAfterRuns.append(OOO_STRING_SVTOOLS_RTF_CELL);
1045 
1046  m_bTableCellOpen = false;
1047  m_bTableAfterCell = true;
1048  m_bWroteCellInfo = false;
1049  if (m_aCells[m_nTableDepth] > 0)
1050  m_aCells[m_nTableDepth]--;
1051 }
1052 
1054 {
1055  SAL_INFO("sw.rtf", __func__ << ", (depth is " << m_nTableDepth << ")");
1056 
1057  // Trying to end the row without writing the required number of cells? Fill with empty ones.
1058  for (sal_uInt32 i = 0; i < m_aCells[m_nTableDepth]; i++)
1059  m_aAfterRuns.append(OOO_STRING_SVTOOLS_RTF_CELL);
1060 
1061  if (m_nTableDepth > 1)
1062  {
1063  m_aAfterRuns.append(
1065  if (!m_aRowDefs.isEmpty())
1066  m_aAfterRuns.append(m_aRowDefs.makeStringAndClear());
1067  else if (!m_aTables.empty())
1068  {
1069  m_aAfterRuns.append(m_aTables.back());
1070  m_aTables.pop_back();
1071  }
1072  m_aAfterRuns.append(OOO_STRING_SVTOOLS_RTF_NESTROW
1073  "}"
1075  }
1076  else
1077  {
1078  if (!m_aTables.empty())
1079  {
1080  m_aAfterRuns.append(m_aTables.back());
1081  m_aTables.pop_back();
1082  }
1084  }
1085  m_bTableRowEnded = true;
1086 }
1087 
1089 {
1090  if (m_nTableDepth > 0)
1091  {
1092  m_nTableDepth--;
1093  m_pTableWrt.reset();
1094  }
1095 
1096  // We closed the table; if it is a nested table, the cell that contains it
1097  // still continues
1098  m_bTableCellOpen = true;
1099 
1100  // Cleans the table helper
1101  m_pTableWrt.reset();
1102 }
1103 
1105 {
1106  if (!pInner)
1107  return;
1108 
1109  // Where are we in the table
1110  sal_uInt32 nRow = pInner->getRow();
1111 
1112  const SwTable* pTable = pInner->getTable();
1113  const SwTableLines& rLines = pTable->GetTabLines();
1114  sal_uInt16 nLinesCount = rLines.size();
1115 
1116  if (pInner->isEndOfCell())
1117  EndTableCell();
1118 
1119  // This is a line end
1120  if (pInner->isEndOfLine())
1121  EndTableRow();
1122 
1123  // This is the end of the table
1124  if (pInner->isEndOfLine() && (nRow + 1) == nLinesCount)
1125  EndTable();
1126 }
1127 
1129 {
1130  m_rExport.Strm()
1131  .WriteCharPtr(SAL_NEWLINE_STRING)
1132  .WriteChar('{')
1133  .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_COLORTBL);
1134  m_rExport.OutColorTable();
1135  OSL_ENSURE(m_aStylesheet.getLength() == 0, "m_aStylesheet is not empty");
1136  m_aStylesheet.append(SAL_NEWLINE_STRING);
1137  m_aStylesheet.append('{');
1138  m_aStylesheet.append(OOO_STRING_SVTOOLS_RTF_STYLESHEET);
1139 }
1140 
1141 void RtfAttributeOutput::EndStyles(sal_uInt16 /*nNumberOfStyles*/)
1142 {
1143  m_rExport.Strm().WriteChar('}');
1144  m_rExport.Strm().WriteOString(m_aStylesheet.makeStringAndClear());
1145  m_rExport.Strm().WriteChar('}');
1146 }
1147 
1148 void RtfAttributeOutput::DefaultStyle() { /* noop, the default style is always 0 in RTF */}
1149 
1150 void RtfAttributeOutput::StartStyle(const OUString& rName, StyleType eType, sal_uInt16 nBase,
1151  sal_uInt16 nNext, sal_uInt16 /*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(OString::number(nId).getStr());
1754  m_aRun->append('}');
1755  }
1756  rStarts.clear();
1757 
1758  for (const auto& rEnd : rEnds)
1759  {
1760  OString rName = OUStringToOString(rEnd, RTL_TEXTENCODING_UTF8);
1761 
1762  // Get the id of the annotation mark
1763  auto it = m_rOpenedAnnotationMarksIds.find(rName);
1764  if (it != m_rOpenedAnnotationMarksIds.end())
1765  {
1766  const sal_Int32 nId = it->second;
1768  m_aRun->append(OString::number(nId).getStr());
1769  m_aRun->append('}');
1770  m_rOpenedAnnotationMarksIds.erase(rName);
1771 
1772  if (m_aPostitFields.find(nId) != m_aPostitFields.end())
1773  {
1774  m_aRunText->append("{");
1775  m_nCurrentAnnotationMarkId = nId;
1776  PostitField(m_aPostitFields[nId]);
1777  m_nCurrentAnnotationMarkId = -1;
1778  m_aRunText->append("}");
1779  }
1780  }
1781  }
1782  rEnds.clear();
1783 }
1784 
1786  const char* pStr, bool bTitlepg)
1787 {
1788  OStringBuffer aSectionBreaks = m_aSectionBreaks;
1789  m_aSectionBreaks.setLength(0);
1790  RtfStringBuffer aRun = m_aRun;
1791  m_aRun.clear();
1792 
1793  m_aSectionHeaders.append(bHeader ? OOO_STRING_SVTOOLS_RTF_HEADERY
1795  m_aSectionHeaders.append(
1796  static_cast<sal_Int32>(m_rExport.m_pCurrentPageDesc->GetMaster().GetULSpace().GetUpper()));
1797  if (bTitlepg)
1798  m_aSectionHeaders.append(OOO_STRING_SVTOOLS_RTF_TITLEPG);
1799  m_aSectionHeaders.append('{');
1800  m_aSectionHeaders.append(pStr);
1801  m_bBufferSectionHeaders = true;
1802  m_rExport.WriteHeaderFooterText(rFormat, bHeader);
1803  m_bBufferSectionHeaders = false;
1804  m_aSectionHeaders.append('}');
1805 
1806  m_aSectionBreaks = aSectionBreaks;
1807  m_aRun = aRun;
1808 }
1809 
1810 namespace
1811 {
1812 void lcl_TextFrameShadow(std::vector<std::pair<OString, OString>>& rFlyProperties,
1813  const SwFrameFormat& rFrameFormat)
1814 {
1815  const SvxShadowItem& aShadowItem = rFrameFormat.GetShadow();
1816  if (aShadowItem.GetLocation() == SvxShadowLocation::NONE)
1817  return;
1818 
1819  rFlyProperties.push_back(std::make_pair<OString, OString>("fShadow", OString::number(1)));
1820 
1821  const Color& rColor = aShadowItem.GetColor();
1822  // We in fact need RGB to BGR, but the transformation is symmetric.
1823  rFlyProperties.push_back(std::make_pair<OString, OString>(
1824  "shadowColor", OString::number(wwUtility::RGBToBGR(rColor))));
1825 
1826  // Twips -> points -> EMUs -- hacky, the intermediate step hides rounding errors on roundtrip.
1827  OString aShadowWidth = OString::number(sal_Int32(aShadowItem.GetWidth() / 20) * 12700);
1828  OString aOffsetX;
1829  OString aOffsetY;
1830  switch (aShadowItem.GetLocation())
1831  {
1832  case SvxShadowLocation::TopLeft:
1833  aOffsetX = "-" + aShadowWidth;
1834  aOffsetY = "-" + aShadowWidth;
1835  break;
1836  case SvxShadowLocation::TopRight:
1837  aOffsetX = aShadowWidth;
1838  aOffsetY = "-" + aShadowWidth;
1839  break;
1840  case SvxShadowLocation::BottomLeft:
1841  aOffsetX = "-" + aShadowWidth;
1842  aOffsetY = aShadowWidth;
1843  break;
1844  case SvxShadowLocation::BottomRight:
1845  aOffsetX = aShadowWidth;
1846  aOffsetY = aShadowWidth;
1847  break;
1848  case SvxShadowLocation::NONE:
1849  case SvxShadowLocation::End:
1850  break;
1851  }
1852  if (!aOffsetX.isEmpty())
1853  rFlyProperties.emplace_back("shadowOffsetX", aOffsetX);
1854  if (!aOffsetY.isEmpty())
1855  rFlyProperties.emplace_back("shadowOffsetY", aOffsetY);
1856 }
1857 
1858 void lcl_TextFrameRelativeSize(std::vector<std::pair<OString, OString>>& rFlyProperties,
1859  const SwFrameFormat& rFrameFormat)
1860 {
1861  const SwFormatFrameSize& rSize = rFrameFormat.GetFrameSize();
1862 
1863  // Relative size of the Text Frame.
1864  const sal_uInt8 nWidthPercent = rSize.GetWidthPercent();
1865  if (nWidthPercent && nWidthPercent != SwFormatFrameSize::SYNCED)
1866  {
1867  rFlyProperties.push_back(
1868  std::make_pair<OString, OString>("pctHoriz", OString::number(nWidthPercent * 10)));
1869 
1870  OString aRelation;
1871  switch (rSize.GetWidthPercentRelation())
1872  {
1873  case text::RelOrientation::PAGE_FRAME:
1874  aRelation = "1"; // page
1875  break;
1876  default:
1877  aRelation = "0"; // margin
1878  break;
1879  }
1880  rFlyProperties.emplace_back(std::make_pair("sizerelh", aRelation));
1881  }
1882  const sal_uInt8 nHeightPercent = rSize.GetHeightPercent();
1883  if (!(nHeightPercent && nHeightPercent != SwFormatFrameSize::SYNCED))
1884  return;
1885 
1886  rFlyProperties.push_back(
1887  std::make_pair<OString, OString>("pctVert", OString::number(nHeightPercent * 10)));
1888 
1889  OString aRelation;
1890  switch (rSize.GetHeightPercentRelation())
1891  {
1892  case text::RelOrientation::PAGE_FRAME:
1893  aRelation = "1"; // page
1894  break;
1895  default:
1896  aRelation = "0"; // margin
1897  break;
1898  }
1899  rFlyProperties.emplace_back(std::make_pair("sizerelv", aRelation));
1900 }
1901 }
1902 
1903 void RtfAttributeOutput::writeTextFrame(const ww8::Frame& rFrame, bool bTextBox)
1904 {
1905  RtfStringBuffer aRunText;
1906  if (bTextBox)
1907  {
1908  m_rExport.setStream();
1909  aRunText = m_aRunText;
1910  m_aRunText.clear();
1911  }
1912 
1913  m_rExport.Strm().WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_SHPTXT);
1914 
1915  {
1916  // Save table state, in case the inner text also contains a table.
1917  ww8::WW8TableInfo::Pointer_t pTableInfoOrig = m_rExport.m_pTableInfo;
1918  m_rExport.m_pTableInfo = std::make_shared<ww8::WW8TableInfo>();
1919  std::unique_ptr<SwWriteTable> pTableWrt(std::move(m_pTableWrt));
1920  sal_uInt32 nTableDepth = m_nTableDepth;
1921 
1922  m_nTableDepth = 0;
1923  /*
1924  * Save m_aRun as we should not lose the opening brace.
1925  * OTOH, just drop the contents of m_aRunText in case something
1926  * would be there, causing a problem later.
1927  */
1928  OString aSave = m_aRun.makeStringAndClear();
1929  // Also back m_bInRun and m_bSingleEmptyRun up.
1930  bool bInRunOrig = m_bInRun;
1931  m_bInRun = false;
1932  bool bSingleEmptyRunOrig = m_bSingleEmptyRun;
1933  m_bSingleEmptyRun = false;
1934  m_rExport.SetRTFFlySyntax(true);
1935 
1936  const SwFrameFormat& rFrameFormat = rFrame.GetFrameFormat();
1937  const SwNodeIndex* pNodeIndex = rFrameFormat.GetContent().GetContentIdx();
1938  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  if (pLeft && pRight && pTop && pBottom && *pLeft == *pRight && *pLeft == *pTop
3562  && *pLeft == *pBottom)
3563  {
3564  const Color& rColor = pTop->GetColor();
3565  // We in fact need RGB to BGR, but the transformation is symmetric.
3566  m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3567  "lineColor", OString::number(wwUtility::RGBToBGR(rColor))));
3568 
3569  if (pTop->GetBorderLineStyle() != SvxBorderLineStyle::NONE)
3570  {
3571  double const fConverted(editeng::ConvertBorderWidthToWord(
3572  pTop->GetBorderLineStyle(), pTop->GetWidth()));
3573  sal_Int32 nWidth = o3tl::convert(fConverted, o3tl::Length::twip, o3tl::Length::emu);
3574  m_aFlyProperties.push_back(
3575  std::make_pair<OString, OString>("lineWidth", OString::number(nWidth)));
3576  }
3577  else
3578  // No border: no line.
3579  m_aFlyProperties.push_back(std::make_pair<OString, OString>("fLine", "0"));
3580  }
3581 
3582  return;
3583  }
3584 
3585  if (rBox.GetTop() && rBox.GetBottom() && rBox.GetLeft() && rBox.GetRight()
3586  && *rBox.GetTop() == *rBox.GetBottom() && *rBox.GetTop() == *rBox.GetLeft()
3587  && *rBox.GetTop() == *rBox.GetRight() && nDist == rBox.GetDistance(SvxBoxItemLine::TOP)
3588  && nDist == rBox.GetDistance(SvxBoxItemLine::LEFT)
3589  && nDist == rBox.GetDistance(SvxBoxItemLine::BOTTOM)
3590  && nDist == rBox.GetDistance(SvxBoxItemLine::RIGHT))
3591  m_aSectionBreaks.append(
3592  OutBorderLine(m_rExport, rBox.GetTop(), OOO_STRING_SVTOOLS_RTF_BOX, nDist));
3593  else
3594  {
3595  SvxShadowLocation eShadowLocation = SvxShadowLocation::NONE;
3596  if (const SfxPoolItem* pItem = GetExport().HasItem(RES_SHADOW))
3597  eShadowLocation = pItem->StaticWhichCast(RES_SHADOW).GetLocation();
3598 
3599  const SvxBoxItemLine* pBrd = aBorders;
3600  const char** pBrdNms = aBorderNames;
3601  for (int i = 0; i < 4; ++i, ++pBrd, ++pBrdNms)
3602  {
3603  if (const editeng::SvxBorderLine* pLn = rBox.GetLine(*pBrd))
3604  {
3605  m_aSectionBreaks.append(OutBorderLine(m_rExport, pLn, *pBrdNms,
3606  rBox.GetDistance(*pBrd), eShadowLocation));
3607  }
3608  }
3609  }
3610 
3611  if (!m_bBufferSectionBreaks)
3612  m_aStyles.append(m_aSectionBreaks.makeStringAndClear());
3613 }
3614 
3615 void RtfAttributeOutput::FormatColumns_Impl(sal_uInt16 nCols, const SwFormatCol& rCol, bool bEven,
3616  SwTwips nPageSize)
3617 {
3618  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_COLS);
3619  m_rExport.OutLong(nCols);
3620 
3621  if (rCol.GetLineAdj() != COLADJ_NONE)
3622  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_LINEBETCOL);
3623 
3624  if (bEven)
3625  {
3626  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_COLSX);
3627  m_rExport.OutLong(rCol.GetGutterWidth(true));
3628  }
3629  else
3630  {
3631  const SwColumns& rColumns = rCol.GetColumns();
3632  for (sal_uInt16 n = 0; n < nCols;)
3633  {
3634  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_COLNO);
3635  m_rExport.OutLong(n + 1);
3636 
3637  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_COLW);
3638  m_rExport.OutLong(rCol.CalcPrtColWidth(n, nPageSize));
3639 
3640  if (++n != nCols)
3641  {
3642  m_rExport.Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_COLSR);
3643  m_rExport.OutLong(rColumns[n - 1].GetRight() + rColumns[n].GetLeft());
3644  }
3645  }
3646  }
3647 }
3648 
3650 {
3651  if (rItem.GetValue())
3652  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_KEEPN);
3653 }
3654 
3656 {
3657  SAL_INFO("sw.rtf", "TODO: " << __func__);
3658 }
3659 
3661 {
3662  if (!rNumbering.IsCount())
3663  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_NOLINE);
3664 }
3665 
3667 {
3668  SvxFrameDirection nDir = rDirection.GetValue();
3669  if (nDir == SvxFrameDirection::Environment)
3670  nDir = GetExport().GetDefaultFrameDirection();
3671 
3672  if (m_rExport.m_bOutPageDescs)
3673  {
3674  if (nDir == SvxFrameDirection::Vertical_RL_TB)
3675  {
3676  m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_STEXTFLOW);
3677  m_aSectionBreaks.append(static_cast<sal_Int32>(1));
3678  if (!m_bBufferSectionBreaks)
3679  m_rExport.Strm().WriteOString(m_aSectionBreaks.makeStringAndClear());
3680  }
3681  return;
3682  }
3683 
3684  if (m_rExport.GetRTFFlySyntax())
3685  {
3686  if (nDir == SvxFrameDirection::Vertical_RL_TB)
3687  {
3688  // Top to bottom non-ASCII font
3689  m_aFlyProperties.push_back(std::make_pair<OString, OString>("txflTextFlow", "3"));
3690  }
3691  else if (rDirection.GetValue() == SvxFrameDirection::Vertical_LR_BT)
3692  {
3693  // Bottom to top non-ASCII font
3694  m_aFlyProperties.push_back(std::make_pair<OString, OString>("txflTextFlow", "2"));
3695  }
3696  return;
3697  }
3698 
3699  if (nDir == SvxFrameDirection::Horizontal_RL_TB)
3700  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_RTLPAR);
3701  else
3702  m_aStyles.append(OOO_STRING_SVTOOLS_RTF_LTRPAR);
3703 }
3704 
3706 {
3707  const std::map<OUString, css::uno::Any>& rMap = rItem.GetGrabBag();
3708  for (const auto& rValue : rMap)
3709  {
3710  if (rValue.first == "ParaTopMarginBeforeAutoSpacing")
3711  {
3712  m_bParaBeforeAutoSpacing = true;
3713  rValue.second >>= m_nParaBeforeSpacing;
3714  m_nParaBeforeSpacing = o3tl::toTwips(m_nParaBeforeSpacing, o3tl::Length::mm100);
3715  }
3716  else if (rValue.first == "ParaBottomMarginAfterAutoSpacing")
3717  {
3718  m_bParaAfterAutoSpacing = true;
3719  rValue.second >>= m_nParaAfterSpacing;
3720  m_nParaAfterSpacing = o3tl::toTwips(m_nParaAfterSpacing, o3tl::Length::mm100);
3721  }
3722  }
3723 }
3724 
3726 
3728 
3730 {
3731  OUString sCmd; // for optional Parameters
3732  switch (pField->GetTyp()->Which())
3733  {
3734  //#i119803# Export user field for RTF filter
3735  case SwFieldIds::User:
3736  sCmd = pField->GetTyp()->GetName();
3737  m_rExport.OutputField(pField, ww::eNONE, sCmd);
3738  break;
3739  default:
3740  m_rExport.OutputField(pField, ww::eUNKNOWN, sCmd);
3741  break;
3742  }
3743 }
3744 
3745 void RtfAttributeOutput::RefField(const SwField& /*rField*/, const OUString& /*rRef*/)
3746 {
3747  SAL_INFO("sw.rtf", "TODO: " << __func__);
3748 }
3749 
3751 {
3752  SAL_INFO("sw.rtf", "TODO: " << __func__);
3753 }
3754 
3755 void RtfAttributeOutput::SetField(const SwField& /*rField*/, ww::eField /*eType*/,
3756  const OUString& /*rCmd*/)
3757 {
3758  SAL_INFO("sw.rtf", "TODO: " << __func__);
3759 }
3760 
3762 {
3763  const SwPostItField& rPField = *static_cast<const SwPostItField*>(pField);
3764 
3765  OString aName = OUStringToOString(rPField.GetName(), RTL_TEXTENCODING_UTF8);
3766  auto it = m_rOpenedAnnotationMarksIds.find(aName);
3767  if (it != m_rOpenedAnnotationMarksIds.end())
3768  {
3769  // In case this field is inside annotation marks, we want to write the
3770  // annotation itself after the annotation mark is closed, not here.
3771  m_aPostitFields[it->second] = &rPField;
3772  return;
3773  }
3774 
3775  m_aRunText->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_ATNID " ");
3776  m_aRunText->append(OUStringToOString(rPField.GetInitials(), m_rExport.GetCurrentEncoding()));
3777  m_aRunText->append("}");
3779  m_aRunText->append(OUStringToOString(rPField.GetPar1(), m_rExport.GetCurrentEncoding()));
3780  m_aRunText->append("}");
3781  m_aRunText->append(OOO_STRING_SVTOOLS_RTF_CHATN);
3782 
3784 
3785  if (m_nCurrentAnnotationMarkId != -1)
3786  {
3788  m_aRunText->append(m_nCurrentAnnotationMarkId);
3789  m_aRunText->append('}');
3790  }
3792  m_aRunText->append(static_cast<sal_Int32>(sw::ms::DateTime2DTTM(rPField.GetDateTime())));
3793  m_aRunText->append('}');
3794  if (const OutlinerParaObject* pObject = rPField.GetTextObject())
3795  m_rExport.SdrExporter().WriteOutliner(*pObject, TXT_ATN);
3796  m_aRunText->append('}');
3797 }
3798 
3800 {
3801  // this is handled in OutputFlyFrame_Impl()
3802  return true;
3803 }
3804 
3806 {
3807  m_aRunText->append("{" OOO_STRING_SVTOOLS_RTF_FIELD
3809  " MACROBUTTON None ");
3810  RunText(pField->GetPar1());
3811  m_aRunText->append("}}");
3812  return false; // do not expand
3813 }
3814 
3816  : AttributeOutputBase("") // ConvertURL isn't used now in RTF output
3817  , m_rExport(rExport)
3818  , m_pPrevPageDesc(nullptr)
3819  , m_nStyleId(0)
3820  , m_nListId(0)
3821  , m_bIsRTL(false)
3822  , m_nScript(i18n::ScriptType::LATIN)
3823  , m_bControlLtrRtl(false)
3824  , m_nNextAnnotationMarkId(0)
3825  , m_nCurrentAnnotationMarkId(-1)
3826  , m_bTableCellOpen(false)
3827  , m_nTableDepth(0)
3828  , m_bTableAfterCell(false)
3829  , m_nColBreakNeeded(false)
3830  , m_bBufferSectionBreaks(false)
3831  , m_bBufferSectionHeaders(false)
3832  , m_bLastTable(true)
3833  , m_bWroteCellInfo(false)
3834  , m_bTableRowEnded(false)
3835  , m_bIsBeforeFirstParagraph(true)
3836  , m_bSingleEmptyRun(false)
3837  , m_bInRun(false)
3838  , m_bInRuby(false)
3839  , m_pFlyFrameSize(nullptr)
3840  , m_bParaBeforeAutoSpacing(false)
3841  , m_nParaBeforeSpacing(0)
3842  , m_bParaAfterAutoSpacing(false)
3843  , m_nParaAfterSpacing(0)
3844 {
3845 }
3846 
3848 
3850 
3851 // These are used by wwFont::WriteRtf()
3852 
3854 void RtfAttributeOutput::StartFont(const OUString& rFamilyName) const
3855 {
3856  // write the font name hex-encoded, but without Unicode - Word at least
3857  // cannot read *both* Unicode and fallback as written by OutString
3859  msfilter::rtfutil::OutString(rFamilyName, m_rExport.GetCurrentEncoding(), false).getStr());
3860 }
3861 
3864 {
3865  m_rExport.Strm().WriteCharPtr(";}");
3867 }
3868 
3870 void RtfAttributeOutput::FontAlternateName(const OUString& rName) const
3871 {
3872  m_rExport.Strm()
3873  .WriteChar('{')
3876  .WriteChar(' ');
3877  // write the font name hex-encoded, but without Unicode - Word at least
3878  // cannot read *both* Unicode and fallback as written by OutString
3879  m_rExport.Strm()
3880  .WriteCharPtr(
3881  msfilter::rtfutil::OutString(rName, m_rExport.GetCurrentEncoding(), false).getStr())
3882  .WriteChar('}');
3883 }
3884 
3887 {
3889  m_rExport.OutULong(nCharSet);
3890  m_rExport.Strm().WriteChar(' ');
3891  m_rExport.SetCurrentEncoding(rtl_getTextEncodingFromWindowsCharset(nCharSet));
3892 }
3893 
3895 void RtfAttributeOutput::FontFamilyType(FontFamily eFamily, const wwFont& rFont) const
3896 {
3898 
3899  const char* pStr = OOO_STRING_SVTOOLS_RTF_FNIL;
3900  switch (eFamily)
3901  {
3902  case FAMILY_ROMAN:
3904  break;
3905  case FAMILY_SWISS:
3907  break;
3908  case FAMILY_MODERN:
3910  break;
3911  case FAMILY_SCRIPT:
3913  break;
3914  case FAMILY_DECORATIVE:
3916  break;
3917  default:
3918  break;
3919  }
3920  m_rExport.OutULong(m_rExport.m_aFontHelper.GetId(rFont)).WriteCharPtr(pStr);
3921 }
3922 
3925 {
3927 
3928  sal_uInt16 nVal = 0;
3929  switch (ePitch)
3930  {
3931  case PITCH_FIXED:
3932  nVal = 1;
3933  break;
3934  case PITCH_VARIABLE:
3935  nVal = 2;
3936  break;
3937  default:
3938  break;
3939  }
3940  m_rExport.OutULong(nVal);
3941 }
3942 
3943 static void lcl_AppendSP(OStringBuffer& rBuffer, const char cName[], const OUString& rValue,
3944  const RtfExport& rExport)
3945 {
3946  rBuffer.append("{" OOO_STRING_SVTOOLS_RTF_SP "{"); // "{\sp{"
3947  rBuffer.append(OOO_STRING_SVTOOLS_RTF_SN " "); //" \sn "
3948  rBuffer.append(cName); //"PropName"
3949  rBuffer.append("}{" OOO_STRING_SVTOOLS_RTF_SV " ");
3950  // "}{ \sv "
3951  rBuffer.append(msfilter::rtfutil::OutString(rValue, rExport.GetCurrentEncoding()));
3952  rBuffer.append("}}");
3953 }
3954 
3955 static OString ExportPICT(const SwFlyFrameFormat* pFlyFrameFormat, const Size& rOrig,
3956  const Size& rRendered, const Size& rMapped, const SwCropGrf& rCr,
3957  const char* pBLIPType, const sal_uInt8* pGraphicAry, sal_uInt64 nSize,
3958  const RtfExport& rExport, SvStream* pStream = nullptr,
3959  bool bWritePicProp = true, const SwAttrSet* pAttrSet = nullptr)
3960 {
3961  OStringBuffer aRet;
3962  if (pBLIPType && nSize && pGraphicAry)
3963  {
3964  bool bIsWMF = std::strcmp(pBLIPType, OOO_STRING_SVTOOLS_RTF_WMETAFILE) == 0;
3965 
3966  aRet.append("{" OOO_STRING_SVTOOLS_RTF_PICT);
3967 
3968  if (pFlyFrameFormat && bWritePicProp)
3969  {
3970  OUString sDescription = pFlyFrameFormat->GetObjDescription();
3971  //write picture properties - wzDescription at first
3972  //looks like: "{\*\picprop{\sp{\sn PropertyName}{\sv PropertyValue}}}"
3973  aRet.append(
3975  lcl_AppendSP(aRet, "wzDescription", sDescription, rExport);
3976  OUString sName = pFlyFrameFormat->GetObjTitle();
3977  lcl_AppendSP(aRet, "wzName", sName, rExport);
3978 
3979  if (pAttrSet)
3980  {
3981  MirrorGraph eMirror = pAttrSet->Get(RES_GRFATR_MIRRORGRF).GetValue();
3982  if (eMirror == MirrorGraph::Vertical || eMirror == MirrorGraph::Both)
3983  // Mirror on the vertical axis is a horizontal flip.
3984  lcl_AppendSP(aRet, "fFlipH", "1", rExport);
3985  }
3986 
3987  aRet.append("}"); //"}"
3988  }
3989 
3990  tools::Long nXCroppedSize = rOrig.Width() - (rCr.GetLeft() + rCr.GetRight());
3991  tools::Long nYCroppedSize = rOrig.Height() - (rCr.GetTop() + rCr.GetBottom());
3992  /* Graphic with a zero height or width, typically copied from webpages, caused crashes. */
3993  if (!nXCroppedSize)
3994  nXCroppedSize = 100;
3995  if (!nYCroppedSize)
3996  nYCroppedSize = 100;
3997 
3998  //Given the original size and taking cropping into account
3999  //first, how much has the original been scaled to get the
4000  //final rendered size
4001  aRet.append(OOO_STRING_SVTOOLS_RTF_PICSCALEX);
4002  aRet.append(static_cast<sal_Int32>((100 * rRendered.Width()) / nXCroppedSize));
4003  aRet.append(OOO_STRING_SVTOOLS_RTF_PICSCALEY);
4004  aRet.append(static_cast<sal_Int32>((100 * rRendered.Height()) / nYCroppedSize));
4005 
4006  aRet.append(OOO_STRING_SVTOOLS_RTF_PICCROPL);
4007  aRet.append(rCr.GetLeft());
4008  aRet.append(OOO_STRING_SVTOOLS_RTF_PICCROPR);
4009  aRet.append(rCr.GetRight());
4010  aRet.append(OOO_STRING_SVTOOLS_RTF_PICCROPT);
4011  aRet.append(rCr.GetTop());
4012  aRet.append(OOO_STRING_SVTOOLS_RTF_PICCROPB);
4013  aRet.append(rCr.GetBottom());
4014 
4015  aRet.append(OOO_STRING_SVTOOLS_RTF_PICW);
4016  aRet.append(static_cast<sal_Int32>(rMapped.Width()));
4017  aRet.append(OOO_STRING_SVTOOLS_RTF_PICH);
4018  aRet.append(static_cast<sal_Int32>(rMapped.Height()));
4019 
4020  aRet.append(OOO_STRING_SVTOOLS_RTF_PICWGOAL);
4021  aRet.append(static_cast<sal_Int32>(rOrig.Width()));
4022  aRet.append(OOO_STRING_SVTOOLS_RTF_PICHGOAL);
4023  aRet.append(static_cast<sal_Int32>(rOrig.Height()));
4024 
4025  aRet.append(pBLIPType);
4026  if (bIsWMF)
4027  {
4028  aRet.append(sal_Int32(8));
4029  msfilter::rtfutil::StripMetafileHeader(pGraphicAry, nSize);
4030  }
4031  aRet.append(SAL_NEWLINE_STRING);
4032  if (pStream)
4033  pStream->WriteOString(aRet.makeStringAndClear());
4034  if (pStream)
4035  msfilter::rtfutil::WriteHex(pGraphicAry, nSize, pStream);
4036  else
4037  aRet.append(msfilter::rtfutil::WriteHex(pGraphicAry, nSize));
4038  aRet.append('}');
4039  if (pStream)
4040  pStream->WriteOString(aRet.makeStringAndClear());
4041  }
4042  return aRet.makeStringAndClear();
4043 }
4044 
4046  SwOLENode& rOLENode, const Size& rSize)
4047 {
4049  Size aSize(rOLENode.GetTwipSize());
4050  Size aRendered(aSize);
4051  aRendered.setWidth(rSize.Width());
4052  aRendered.setHeight(rSize.Height());
4053  const Graphic* pGraphic = rOLENode.GetGraphic();
4054  Size aMapped(pGraphic->GetPrefSize());
4055  auto& rCr = static_cast<const SwCropGrf&>(rOLENode.GetAttr(RES_GRFATR_CROPGRF));
4056  const char* pBLIPType = OOO_STRING_SVTOOLS_RTF_PNGBLIP;
4057  const sal_uInt8* pGraphicAry = nullptr;
4058  SvMemoryStream aStream;
4059  if (GraphicConverter::Export(aStream, *pGraphic, ConvertDataFormat::PNG) != ERRCODE_NONE)
4060  SAL_WARN("sw.rtf", "failed to export the graphic");
4061  sal_uInt32 nSize = aStream.TellEnd();
4062  pGraphicAry = static_cast<sal_uInt8 const*>(aStream.GetData());
4063  m_aRunText->append(ExportPICT(pFlyFrameFormat, aSize, aRendered, aMapped, rCr, pBLIPType,
4064  pGraphicAry, nSize, m_rExport));
4065  m_aRunText->append("}"); // shppict
4068  SvMemoryStream aWmfStream;
4069  if (GraphicConverter::Export(aWmfStream, *pGraphic, ConvertDataFormat::WMF) != ERRCODE_NONE)
4070  SAL_WARN("sw.rtf", "failed to export the graphic");
4071  nSize = aWmfStream.TellEnd();
4072  pGraphicAry = static_cast<sal_uInt8 const*>(aWmfStream.GetData());
4073  m_aRunText->append(ExportPICT(pFlyFrameFormat, aSize, aRendered, aMapped, rCr, pBLIPType,
4074  pGraphicAry, nSize, m_rExport));
4075  m_aRunText->append("}"); // nonshppict
4076 }
4077 
4079  SwOLENode& rOLENode, const Size& rSize)
4080 {
4081  uno::Reference<embed::XEmbeddedObject> xObj(rOLENode.GetOLEObj().GetOleRef());
4082  sal_Int64 nAspect = rOLENode.GetAspect();
4083  svt::EmbeddedObjectRef aObjRef(xObj, nAspect);
4084  SvGlobalName aObjName(aObjRef->getClassID());
4085 
4086  if (!SotExchange::IsMath(aObjName))
4087  return false;
4088 
4090  uno::Reference<util::XCloseable> xClosable = xObj->getComponent();
4091  if (!xClosable.is())
4092  return false;
4093  // gcc4.4 (and 4.3 and possibly older) have a problem with dynamic_cast directly to the target class,
4094  // so help it with an intermediate cast. I'm not sure what exactly the problem is, seems to be unrelated
4095  // to RTLD_GLOBAL, so most probably a gcc bug.
4096  auto pBase
4097  = dynamic_cast<oox::FormulaExportBase*>(dynamic_cast<SfxBaseModel*>(xClosable.get()));
4098  assert(pBase != nullptr);
4099  OStringBuffer aBuf;
4100  if (pBase)
4101  pBase->writeFormulaRtf(aBuf, m_rExport.GetCurrentEncoding());
4102  m_aRunText->append(aBuf);
4103  // Replacement graphic.
4105  FlyFrameOLEReplacement(pFlyFrameFormat, rOLENode, rSize);
4106  m_aRunText->append("}"); // mmathPict
4107  m_aRunText->append("}"); // mmath
4108 
4109  return true;
4110 }
4111 
4112 void RtfAttributeOutput::FlyFrameOLE(const SwFlyFrameFormat* pFlyFrameFormat, SwOLENode& rOLENode,
4113  const Size& rSize)
4114 {
4115  if (FlyFrameOLEMath(pFlyFrameFormat, rOLENode, rSize))
4116  return;
4117 
4118  FlyFrameOLEReplacement(pFlyFrameFormat, rOLENode, rSize);
4119 }
4120 
4122  const SwGrfNode* pGrfNode)
4123 {
4124  SvMemoryStream aStream;
4125  const sal_uInt8* pGraphicAry = nullptr;
4126  sal_uInt32 nSize = 0;
4127 
4128  const Graphic& rGraphic(pGrfNode->GetGrf());
4129 
4130  // If there is no graphic there is not much point in parsing it
4131  if (rGraphic.GetType() == GraphicType::NONE)
4132  return;
4133 
4134  ConvertDataFormat aConvertDestinationFormat = ConvertDataFormat::WMF;
4135  const char* pConvertDestinationBLIPType = OOO_STRING_SVTOOLS_RTF_WMETAFILE;
4136 
4137  GfxLink aGraphicLink;
4138  const char* pBLIPType = nullptr;
4139  if (rGraphic.IsGfxLink())
4140  {
4141  aGraphicLink = rGraphic.GetGfxLink();
4142  nSize = aGraphicLink.GetDataSize();
4143  pGraphicAry = aGraphicLink.GetData();
4144  switch (aGraphicLink.GetType())
4145  {
4146  // #i15508# trying to add BMP type for better exports, need to check if this works
4147  // checked, does not work. Also need to reset pGraphicAry to NULL to force conversion
4148  // to PNG, else the BMP array will be used.
4149  // It may work using direct DIB data, but that needs to be checked eventually
4150  //
4151  // #i15508# before GfxLinkType::NativeBmp was added the graphic data
4152  // (to be hold in pGraphicAry) was not available; thus for now to stay
4153  // compatible, keep it that way by assigning NULL value to pGraphicAry
4154  case GfxLinkType::NativeBmp:
4155  // pBLIPType = OOO_STRING_SVTOOLS_RTF_WBITMAP;
4156  pGraphicAry = nullptr;
4157  break;
4158 
4159  case GfxLinkType::NativeJpg:
4160  pBLIPType = OOO_STRING_SVTOOLS_RTF_JPEGBLIP;
4161  break;
4162  case GfxLinkType::NativePng:
4163  pBLIPType = OOO_STRING_SVTOOLS_RTF_PNGBLIP;
4164  break;
4165  case GfxLinkType::NativeWmf:
4166  pBLIPType = aGraphicLink.IsEMF() ? OOO_STRING_SVTOOLS_RTF_EMFBLIP
4168  break;
4169  case GfxLinkType::NativeGif:
4170  // GIF is not supported by RTF, but we override default conversion to WMF, PNG seems fits better here.
4171  aConvertDestinationFormat = ConvertDataFormat::PNG;
4172  pConvertDestinationBLIPType = OOO_STRING_SVTOOLS_RTF_PNGBLIP;
4173  break;
4174  default:
4175  break;
4176  }
4177  }
4178 
4179  GraphicType eGraphicType = rGraphic.GetType();
4180  if (!pGraphicAry)
4181  {
4182  if (ERRCODE_NONE
4183  == GraphicConverter::Export(aStream, rGraphic,
4184  (eGraphicType == GraphicType::Bitmap)
4185  ? ConvertDataFormat::PNG
4186  : ConvertDataFormat::WMF))
4187  {
4188  pBLIPType = (eGraphicType == GraphicType::Bitmap) ? OOO_STRING_SVTOOLS_RTF_PNGBLIP
4190  nSize = aStream.TellEnd();
4191  pGraphicAry = static_cast<sal_uInt8 const*>(aStream.GetData());
4192  }
4193  }
4194 
4195  Size aMapped(eGraphicType == GraphicType::Bitmap ? rGraphic.GetSizePixel()
4196  : rGraphic.GetPrefSize());
4197 
4198  auto& rCr = static_cast<const SwCropGrf&>(pGrfNode->GetAttr(RES_GRFATR_CROPGRF));
4199 
4200  //Get original size in twips
4201  Size aSize(pGrfNode->GetTwipSize());
4202  Size aRendered(aSize);
4203 
4204  const SwFormatFrameSize& rS = pFlyFrameFormat->GetFrameSize();
4205  aRendered.setWidth(rS.GetWidth());
4206  aRendered.setHeight(rS.GetHeight());
4207 
4208  ww8::Frame* pFrame = nullptr;
4209  for (auto& rFrame : m_rExport.m_aFrames)
4210  {
4211  if (pFlyFrameFormat == &rFrame.GetFrameFormat())
4212  {
4213  pFrame = &rFrame;
4214  break;
4215  }
4216  }
4217 
4218  /*
4219  If the graphic is not of type WMF then we will have to store two
4220  graphics, one in the native format wrapped in shppict, and the other in
4221  the wmf format wrapped in nonshppict, so as to keep wordpad happy. If its
4222  a wmf already then we don't need any such wrapping
4223  */
4224  bool bIsWMF = pBLIPType && std::strcmp(pBLIPType, OOO_STRING_SVTOOLS_RTF_WMETAFILE) == 0;
4225  const SwAttrSet* pAttrSet = pGrfNode->GetpSwAttrSet();
4226  if (!pFrame || pFrame->IsInline())
4227  {
4228  if (!bIsWMF)
4231  }
4232  else
4233  {
4237  m_pFlyFrameSize = &aRendered;
4238  m_rExport.m_pParentFrame = pFrame;
4240  m_rExport.SetRTFFlySyntax(true);
4241  m_rExport.OutputFormat(pFrame->GetFrameFormat(), false, false, true);
4243  m_rExport.SetRTFFlySyntax(false);
4244  m_rExport.m_pParentFrame = nullptr;
4245  m_pFlyFrameSize = nullptr;
4246  std::vector<std::pair<OString, OString>> aFlyProperties{
4247  { "shapeType", OString::number(ESCHER_ShpInst_PictureFrame) },
4248 
4249  { "wzDescription", msfilter::rtfutil::OutString(pFlyFrameFormat->GetObjDescription(),
4251  { "wzName", msfilter::rtfutil::OutString(pFlyFrameFormat->GetObjTitle(),
4253  };
4254 
4255  // If we have a wrap polygon, then handle that here.
4256  if (pFlyFrameFormat->GetSurround().IsContour())
4257  {
4258  if (const SwNoTextNode* pNd
4259  = sw::util::GetNoTextNodeFromSwFrameFormat(*pFlyFrameFormat))
4260  {
4261  const tools::PolyPolygon* pPolyPoly = pNd->HasContour();
4262  if (pPolyPoly && pPolyPoly->Count())
4263  {
4265  *pPolyPoly, pNd, /*bCorrectCrop=*/true);
4266  OStringBuffer aVerticies;
4267  for (sal_uInt16 i = 0; i < aPoly.GetSize(); ++i)
4268  aVerticies.append(";(" + OString::number(aPoly[i].X()) + ","
4269  + OString::number(aPoly[i].Y()) + ")");
4270  aFlyProperties.push_back(std::make_pair<OString, OString>(
4271  "pWrapPolygonVertices",
4272  "8;" + OString::number(aPoly.GetSize()) + aVerticies.makeStringAndClear()));
4273  }
4274  }
4275  }
4276 
4277  // Below text, behind document, opaque: they all refer to the same thing.
4278  if (!pFlyFrameFormat->GetOpaque().GetValue())
4279  aFlyProperties.push_back(std::make_pair<OString, OString>("fBehindDocument", "1"));
4280 
4281  if (pAttrSet)
4282  {
4283  if (Degree10 nRot10 = pAttrSet->Get(RES_GRFATR_ROTATION).GetValue())
4284  {
4285  // See writerfilter::rtftok::RTFSdrImport::applyProperty(),
4286  // positive rotation angles are clockwise in RTF, we have them
4287  // as counter-clockwise.
4288  // Additionally, RTF type is 0..360*2^16, our is 0..360*10.
4289  sal_Int32 nRot = nRot10.get() * -1 * RTF_MULTIPLIER / 10;
4290  aFlyProperties.emplace_back("rotation", OString::number(nRot));
4291  }
4292  }
4293 
4294  for (const std::pair<OString, OString>& rPair : aFlyProperties)
4295  {
4298  m_rExport.Strm().WriteOString(rPair.first);
4300  m_rExport.Strm().WriteOString(rPair.second);
4301  m_rExport.Strm().WriteCharPtr("}}");
4302  }
4304  " pib"
4305  "}{" OOO_STRING_SVTOOLS_RTF_SV " ");
4306  }
4307 
4308  bool bWritePicProp = !pFrame || pFrame->IsInline();
4309  if (pBLIPType)
4310  ExportPICT(pFlyFrameFormat, aSize, aRendered, aMapped, rCr, pBLIPType, pGraphicAry, nSize,
4311  m_rExport, &m_rExport.Strm(), bWritePicProp, pAttrSet);
4312  else
4313  {
4314  aStream.Seek(0);
4315  if (GraphicConverter::Export(aStream, rGraphic, aConvertDestinationFormat) != ERRCODE_NONE)
4316  SAL_WARN("sw.rtf", "failed to export the graphic");
4317  pBLIPType = pConvertDestinationBLIPType;
4318  nSize = aStream.TellEnd();
4319  pGraphicAry = static_cast<sal_uInt8 const*>(aStream.GetData());
4320 
4321  ExportPICT(pFlyFrameFormat, aSize, aRendered, aMapped, rCr, pBLIPType, pGraphicAry, nSize,
4322  m_rExport, &m_rExport.Strm(), bWritePicProp, pAttrSet);
4323  }
4324 
4325  if (!pFrame || pFrame->IsInline())
4326  {
4327  if (!bIsWMF)
4328  {
4331 
4332  aStream.Seek(0);
4333  if (GraphicConverter::Export(aStream, rGraphic, ConvertDataFormat::WMF) != ERRCODE_NONE)
4334  SAL_WARN("sw.rtf", "failed to export the graphic");
4336  nSize = aStream.TellEnd();
4337  pGraphicAry = static_cast<sal_uInt8 const*>(aStream.GetData());
4338 
4339  ExportPICT(pFlyFrameFormat, aSize, aRendered, aMapped, rCr, pBLIPType, pGraphicAry,
4340  nSize, m_rExport, &m_rExport.Strm());
4341 
4342  m_rExport.Strm().WriteChar('}');
4343  }
4344  }
4345  else
4346  m_rExport.Strm().WriteCharPtr("}}}}"); // Close SV, SP, SHPINST and SHP.
4347 
4349 }
4350 
4351 void RtfAttributeOutput::BulletDefinition(int /*nId*/, const Graphic& rGraphic, Size aSize)
4352 {
4355 
4357  m_rExport.OutULong(aSize.Width());
4359  m_rExport.OutULong(aSize.Height());
4360 
4362  const sal_uInt8* pGraphicAry = nullptr;
4363  SvMemoryStream aStream;
4364  if (GraphicConverter::Export(aStream, rGraphic, ConvertDataFormat::PNG) != ERRCODE_NONE)
4365  SAL_WARN("sw.rtf", "failed to export the numbering picture bullet");
4366  sal_uInt32 nSize = aStream.TellEnd();
4367  pGraphicAry = static_cast<sal_uInt8 const*>(aStream.GetData());
4368  msfilter::rtfutil::WriteHex(pGraphicAry, nSize, &m_rExport.Strm());
4369  m_rExport.Strm().WriteCharPtr("}}"); // pict, shppict
4370 }
4371 
4373 {
4374  if (!rRtlGutter.GetValue())
4375  {
4376  return;
4377  }
4378 
4380 }
4381 
4382 /* 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:1081
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:679
#define OOO_STRING_SVTOOLS_RTF_ANIMTEXT
#define OOO_STRING_SVTOOLS_RTF_ULTHDASHD
sal_uInt16 GetRowSpan() const
Definition: wrtswtbl.hxx:78
#define OOO_STRING_SVTOOLS_RTF_ALANG
#define OOO_STRING_SVTOOLS_RTF_BRDRINSET
#define OOO_STRING_SVTOOLS_RTF_COLNO
sal_uInt16 Count() const
sal_Int32 GetLeft() const
std::vector< SwColumn > SwColumns
Definition: fmtclds.hxx:57
void FormatKeep(const SvxFormatKeepItem &rItem) override
Sfx item RES_KEEP.
#define OOO_STRING_SVTOOLS_RTF_FSWISS
FAMILY_SCRIPT
void EndRuby(const SwTextNode &rNode, sal_Int32 nPos) override
Output ruby end.
#define OOO_STRING_SVTOOLS_RTF_SN
OUString GetObjDescription() const
Definition: atrfrm.cxx:3221
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:177
void CharBackground(const SvxBrushItem &rBrush) override
Sfx item RES_CHRATR_BACKGROUND.
#define OOO_STRING_SVTOOLS_RTF_SBASEDON
void FormatVertOrientation(const SwFormatVertOrient &rFlyVert) override
Sfx item RES_VERT_ORIENT.
bool IsTransparent() const
#define OOO_STRING_SVTOOLS_RTF_ULDASH
sal_uInt16 GetCountBy() const
Definition: lineinfo.hxx:74
#define OOO_STRING_SVTOOLS_RTF_S
void PostitField(const SwField *pField) override
eFORMCHECKBOX
#define OOO_STRING_SVTOOLS_RTF_CLBRDRR
const SwNumFormat * GetNumFormat(sal_uInt16 i) const
Definition: number.cxx: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:293
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:940
constexpr Point convert(const Point &rPoint, o3tl::Length eFrom, o3tl::Length eTo)
#define OOO_STRING_SVTOOLS_RTF_FORMFIELD
SvStream & Strm()
Definition: rtfexport.cxx:1059
sal_Int64 n
GraphicType
void SectionRtlGutter(const SfxBoolItem &rRtlGutter) override
RES_RTL_GUTTER.
#define OOO_STRING_SVTOOLS_RTF_AF
#define OOO_STRING_SVTOOLS_RTF_FFNAME
#define OOO_STRING_SVTOOLS_RTF_LISTLEVEL
void ParaNumRule_Impl(const SwTextNode *pTextNd, sal_Int32 nLvl, sal_Int32 nNumId) override
Sfx item RES_PARATR_NUMRULE.
#define OOO_STRING_SVTOOLS_RTF_ATNREF
#define OOO_STRING_SVTOOLS_RTF_SHPBXCOLUMN
SVX_NUM_CIRCLE_NUMBER
#define OOO_STRING_SVTOOLS_RTF_SL
void ParaSplit(const SvxFormatSplitItem &rSplit) override
Sfx item RES_PARATR_SPLIT.
void StartFont(const OUString &rFamilyName) const
Start the font.
constexpr sal_uInt8 MAXLEVEL
Definition: swtypes.hxx:93
aBuf
void CharFontCJK(const SvxFontItem &rFont) override
Sfx item RES_CHRATR_CJK_FONT.
LINESTYLE_BOLDWAVE
sal_Int16 nId
sal_uInt16 GetDistance(SvxBoxItemLine nLine) const
void FlyFrameGraphic(const SwFlyFrameFormat *pFlyFrameFormat, const SwGrfNode *pGrfNode)
Output graphic fly frames.
#define OOO_STRING_SVTOOLS_RTF_PICT
void clear()
Similar to ->setLength(0), but for all buffers.
void TableInfoCell(ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner) override
virtual OUString GetPar1() const override
Author.
Definition: docufld.cxx:1800
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:358
#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:121
#define OOO_STRING_SVTOOLS_RTF_PICSCALEY
MirrorGraph
Definition: grfatr.hxx:31
void EndStyles(sal_uInt16 nNumberOfStyles) override
End of the styles table.
#define LO_STRING_SVTOOLS_RTF_MMATH
#define LO_STRING_SVTOOLS_RTF_MMATHPICT
void RefField(const SwField &rField, const OUString &rRef) override
#define OOO_STRING_SVTOOLS_RTF_INTBL
SvxFrameDirection
#define OOO_STRING_SVTOOLS_RTF_CLTXTBRL
#define OOO_STRING_SVTOOLS_RTF_SOUTLVL
#define OOO_STRING_SVTOOLS_RTF_BKMKEND
void CharLanguage(const SvxLanguageItem &rLanguage) override
Sfx item RES_CHRATR_LANGUAGE.
#define OOO_STRING_SVTOOLS_RTF_OUTLINELEVEL
#define OOO_STRING_SVTOOLS_RTF_FLYANCHOR
#define OOO_STRING_SVTOOLS_RTF_FSCRIPT
void StartAbstractNumbering(sal_uInt16 nId) override
Start of the abstract numbering definition instance.
#define OOO_STRING_SVTOOLS_RTF_CLVMRG
#define OOO_STRING_SVTOOLS_RTF_RTLPAR
bool IsEndNote() const
Definition: fmtftn.hxx:71
#define DFLT_ESC_AUTO_SUB
#define OOO_STRING_SVTOOLS_RTF_LEVELSTARTAT
#define OOO_STRING_SVTOOLS_RTF_FLDRSLT
void StartStyles() override
Start of the styles table.
void FormatFrameSize(const SwFormatFrameSize &rSize) override
Sfx item RES_FRM_SIZE.
FAMILY_ROMAN
void SectionTitlePage() override
Has different headers/footers for the title page.
void CharPostureCTL(const SvxPostureItem &rPosture) override
Sfx item RES_CHRATR_CTL_POSTURE.
void SectFootnoteEndnotePr() override
for footnote/endnote section properties
#define OOO_STRING_SVTOOLS_RTF_ACCUNDERDOT
#define OOO_STRING_SVTOOLS_RTF_SFTNNALC
void FlyFrameOLE(const SwFlyFrameFormat *pFlyFrameFormat, SwOLENode &rOLENode, const Size &rSize)
#define OOO_STRING_SVTOOLS_RTF_LTRCH
const sal_uInt8 ColumnBreak
void SectionBiDi(bool bBiDi) override
Columns populated from right/numbers on the right side?
const editeng::SvxBorderLine * GetRight() const
bool m_bSingleEmptyRun
If we're in a paragraph that has a single empty run only.
#define OOO_STRING_SVTOOLS_RTF_SBKNONE
void CharCaseMap(const SvxCaseMapItem &rCaseMap) override
Sfx item Sfx item RES_CHRATR_CASEMAP.
void SectionBreak(sal_uInt8 nC, bool bBreakAfter, const WW8_SepInfo *pSectionInfo=nullptr, bool bExtraPageBreak=false) override
Write a section break msword::ColumnBreak or msword::PageBreak.
sal_Int16 GetRelationOrient() const
Definition: fmtornt.hxx:55
#define OOO_STRING_SVTOOLS_RTF_CLVERTALB
#define OOO_STRING_SVTOOLS_RTF_PICH
rtl_TextEncoding GetDefaultEncoding() const
Definition: rtfexport.hxx:172
#define OOO_STRING_SVTOOLS_RTF_MARGRSXN
EmbeddedObjectRef * pObject