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