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