android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / filter / ww8 / rtfattributeoutput.cxx
blob5c20be552480bce8d77e03f3c99de1894bf35b03
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "rtfattributeoutput.hxx"
21 #include <memory>
22 #include <cstring>
23 #include "rtfsdrexport.hxx"
24 #include "writerwordglue.hxx"
25 #include "ww8par.hxx"
26 #include <fmtcntnt.hxx>
27 #include <rtl/tencinfo.h>
28 #include <sal/log.hxx>
29 #include <sot/exchange.hxx>
30 #include <svtools/rtfkeywd.hxx>
31 #include <editeng/fontitem.hxx>
32 #include <editeng/tstpitem.hxx>
33 #include <editeng/adjustitem.hxx>
34 #include <editeng/spltitem.hxx>
35 #include <editeng/widwitem.hxx>
36 #include <editeng/postitem.hxx>
37 #include <editeng/wghtitem.hxx>
38 #include <editeng/kernitem.hxx>
39 #include <editeng/crossedoutitem.hxx>
40 #include <editeng/cmapitem.hxx>
41 #include <editeng/wrlmitem.hxx>
42 #include <editeng/udlnitem.hxx>
43 #include <editeng/langitem.hxx>
44 #include <editeng/escapementitem.hxx>
45 #include <editeng/fhgtitem.hxx>
46 #include <editeng/colritem.hxx>
47 #include <editeng/hyphenzoneitem.hxx>
48 #include <editeng/contouritem.hxx>
49 #include <editeng/shdditem.hxx>
50 #include <editeng/autokernitem.hxx>
51 #include <editeng/emphasismarkitem.hxx>
52 #include <editeng/twolinesitem.hxx>
53 #include <editeng/charscaleitem.hxx>
54 #include <editeng/charrotateitem.hxx>
55 #include <editeng/charreliefitem.hxx>
56 #include <editeng/paravertalignitem.hxx>
57 #include <editeng/blinkitem.hxx>
58 #include <editeng/charhiddenitem.hxx>
59 #include <editeng/boxitem.hxx>
60 #include <editeng/brushitem.hxx>
61 #include <editeng/ulspitem.hxx>
62 #include <editeng/shaditem.hxx>
63 #include <editeng/keepitem.hxx>
64 #include <editeng/frmdiritem.hxx>
65 #include <editeng/opaqitem.hxx>
66 #include <o3tl/unit_conversion.hxx>
67 #include <svx/svdouno.hxx>
68 #include <filter/msfilter/rtfutil.hxx>
69 #include <svx/xfillit0.hxx>
70 #include <svx/xflgrit.hxx>
71 #include <docufld.hxx>
72 #include <fmtclds.hxx>
73 #include <fmtrowsplt.hxx>
74 #include <fmtline.hxx>
75 #include <fmtanchr.hxx>
76 #include <ftninfo.hxx>
77 #include <htmltbl.hxx>
78 #include <ndgrf.hxx>
79 #include <pagedesc.hxx>
80 #include <swmodule.hxx>
81 #include <txtftn.hxx>
82 #include <txtinet.hxx>
83 #include <grfatr.hxx>
84 #include <ndole.hxx>
85 #include <lineinfo.hxx>
86 #include <redline.hxx>
87 #include <rtf.hxx>
88 #include <vcl/cvtgrf.hxx>
89 #include <oox/mathml/imexport.hxx>
90 #include <com/sun/star/i18n/ScriptType.hpp>
91 #include <svl/grabbagitem.hxx>
92 #include <frmatr.hxx>
93 #include <swtable.hxx>
94 #include <formatflysplit.hxx>
95 #include <fmtwrapinfluenceonobjpos.hxx>
96 #include "rtfexport.hxx"
98 using namespace ::com::sun::star;
99 using namespace sw::util;
101 static OString OutTBLBorderLine(RtfExport const& rExport, const editeng::SvxBorderLine* pLine,
102 const char* pStr)
104 OStringBuffer aRet;
105 if (pLine && !pLine->isEmpty())
107 aRet.append(pStr);
108 // single line
109 switch (pLine->GetBorderLineStyle())
111 case SvxBorderLineStyle::SOLID:
113 if (SvxBorderLineWidth::Hairline == pLine->GetWidth())
114 aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRHAIR);
115 else
116 aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRS);
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:
130 aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRTNTHSG);
131 break;
132 case SvxBorderLineStyle::THINTHICK_MEDIUMGAP:
133 aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRTNTHMG);
134 break;
135 case SvxBorderLineStyle::THINTHICK_LARGEGAP:
136 aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRTNTHLG);
137 break;
138 case SvxBorderLineStyle::THICKTHIN_SMALLGAP:
139 aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRTHTNSG);
140 break;
141 case SvxBorderLineStyle::THICKTHIN_MEDIUMGAP:
142 aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRTHTNMG);
143 break;
144 case SvxBorderLineStyle::THICKTHIN_LARGEGAP:
145 aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRTHTNLG);
146 break;
147 case SvxBorderLineStyle::EMBOSSED:
148 aRet.append(OOO_STRING_SVTOOLS_RTF_BRDREMBOSS);
149 break;
150 case SvxBorderLineStyle::ENGRAVED:
151 aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRENGRAVE);
152 break;
153 case SvxBorderLineStyle::OUTSET:
154 aRet.append(OOO_STRING_SVTOOLS_RTF_BRDROUTSET);
155 break;
156 case SvxBorderLineStyle::INSET:
157 aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRINSET);
158 break;
159 case SvxBorderLineStyle::FINE_DASHED:
160 aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRDASHSM);
161 break;
162 case SvxBorderLineStyle::DASH_DOT:
163 aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRDASHD);
164 break;
165 case SvxBorderLineStyle::DASH_DOT_DOT:
166 aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRDASHDD);
167 break;
168 case SvxBorderLineStyle::NONE:
169 default:
170 aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRNONE);
171 break;
174 double const fConverted(
175 ::editeng::ConvertBorderWidthToWord(pLine->GetBorderLineStyle(), pLine->GetWidth()));
176 if (255 >= pLine->GetWidth()) // That value comes from RTF specs
178 aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRW
179 + OString::number(static_cast<sal_Int32>(fConverted)));
181 else
183 // use \brdrth to double the value range...
184 aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRTH OOO_STRING_SVTOOLS_RTF_BRDRW
185 + OString::number(static_cast<sal_Int32>(fConverted) / 2));
188 aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRCF
189 + OString::number(static_cast<sal_Int32>(rExport.GetColor(pLine->GetColor()))));
191 else // tdf#129758 "no border" may be needed to override style
193 aRet.append(OString::Concat(pStr) + OOO_STRING_SVTOOLS_RTF_BRDRNONE);
195 return aRet.makeStringAndClear();
198 static OString OutBorderLine(RtfExport const& rExport, const editeng::SvxBorderLine* pLine,
199 const char* pStr, sal_uInt16 nDist,
200 SvxShadowLocation eShadowLocation = SvxShadowLocation::NONE)
202 OStringBuffer aRet(OutTBLBorderLine(rExport, pLine, pStr));
203 if (pLine)
205 aRet.append(OOO_STRING_SVTOOLS_RTF_BRSP + OString::number(static_cast<sal_Int32>(nDist)));
207 if (eShadowLocation == SvxShadowLocation::BottomRight)
208 aRet.append(LO_STRING_SVTOOLS_RTF_BRDRSH);
209 return aRet.makeStringAndClear();
212 void RtfAttributeOutput::RTLAndCJKState(bool bIsRTL, sal_uInt16 nScript)
214 m_bIsRTL = bIsRTL;
215 m_nScript = nScript;
216 m_bControlLtrRtl = true;
219 sal_Int32 RtfAttributeOutput::StartParagraph(ww8::WW8TableNodeInfo::Pointer_t pTextNodeInfo,
220 bool /*bGenerateParaId*/)
222 if (m_bIsBeforeFirstParagraph && m_rExport.m_nTextTyp != TXT_HDFT)
223 m_bIsBeforeFirstParagraph = false;
225 // Output table/table row/table cell starts if needed
226 if (pTextNodeInfo)
228 sal_uInt32 nRow = pTextNodeInfo->getRow();
229 sal_uInt32 nCell = pTextNodeInfo->getCell();
231 // New cell/row?
232 if (m_nTableDepth > 0 && !m_bTableCellOpen)
234 ww8::WW8TableNodeInfoInner::Pointer_t pDeepInner(
235 pTextNodeInfo->getInnerForDepth(m_nTableDepth));
236 OSL_ENSURE(pDeepInner, "TableNodeInfoInner not found");
237 // Make sure we always start a row between ending one and starting a cell.
238 // In case of subtables, we may not get the first cell.
239 if (pDeepInner && (pDeepInner->getCell() == 0 || m_bTableRowEnded))
241 StartTableRow(pDeepInner);
244 StartTableCell();
247 // Again, if depth was incremented, start a new table even if we skipped the first cell.
248 if ((nRow == 0 && nCell == 0) || (m_nTableDepth == 0 && pTextNodeInfo->getDepth()))
250 // Do we have to start the table?
251 // [If we are at the right depth already, it means that we
252 // continue the table cell]
253 sal_uInt32 nCurrentDepth = pTextNodeInfo->getDepth();
255 if (nCurrentDepth > m_nTableDepth)
257 // Start all the tables that begin here
258 for (sal_uInt32 nDepth = m_nTableDepth + 1; nDepth <= pTextNodeInfo->getDepth();
259 ++nDepth)
261 ww8::WW8TableNodeInfoInner::Pointer_t pInner(
262 pTextNodeInfo->getInnerForDepth(nDepth));
264 m_bLastTable = (nDepth == pTextNodeInfo->getDepth());
265 StartTable();
266 StartTableRow(pInner);
267 StartTableCell();
270 m_nTableDepth = nCurrentDepth;
275 OSL_ENSURE(m_aRun.getLength() == 0, "m_aRun is not empty");
276 return 0;
279 void RtfAttributeOutput::EndParagraph(ww8::WW8TableNodeInfoInner::Pointer_t pTextNodeInfoInner)
281 bool bLastPara = false;
282 if (m_rExport.m_nTextTyp == TXT_FTN || m_rExport.m_nTextTyp == TXT_EDN
283 || m_rExport.m_rDoc.IsClipBoard())
285 // We're ending a paragraph that is the last paragraph of a footnote or endnote, or of clipboard.
286 bLastPara
287 = m_rExport.GetCurrentNodeIndex()
288 && m_rExport.GetCurrentNodeIndex() == m_rExport.m_pCurPam->End()->GetNodeIndex();
291 FinishTableRowCell(pTextNodeInfoInner);
293 RtfStringBuffer aParagraph;
295 aParagraph.appendAndClear(m_aRun);
296 aParagraph->append(m_aAfterRuns);
297 m_aAfterRuns.setLength(0);
298 if (m_bTableAfterCell)
299 m_bTableAfterCell = false;
300 else
302 aParagraph->append(SAL_NEWLINE_STRING);
303 // RTF_PAR at the end of the footnote or clipboard, would cause an additional empty paragraph.
304 if (!bLastPara)
306 aParagraph->append(OOO_STRING_SVTOOLS_RTF_PAR);
307 aParagraph->append(' ');
310 if (m_nColBreakNeeded)
312 aParagraph->append(OOO_STRING_SVTOOLS_RTF_COLUMN);
313 m_nColBreakNeeded = false;
316 if (!m_bBufferSectionHeaders)
317 aParagraph.makeStringAndClear(this);
318 else
319 m_aSectionHeaders.append(aParagraph.makeStringAndClear());
322 void RtfAttributeOutput::EmptyParagraph()
324 m_rExport.Strm()
325 .WriteOString(SAL_NEWLINE_STRING)
326 .WriteOString(OOO_STRING_SVTOOLS_RTF_PAR)
327 .WriteChar(' ');
330 void RtfAttributeOutput::SectionBreaks(const SwNode& rNode)
332 SwNodeIndex aNextIndex(rNode, 1);
333 if (rNode.IsTextNode())
335 OSL_ENSURE(m_aStyles.getLength() == 0, "m_aStyles is not empty");
337 // output page/section breaks
338 m_rExport.Strm().WriteOString(m_aSectionBreaks);
339 m_aSectionBreaks.setLength(0);
340 m_bBufferSectionBreaks = true;
342 // output section headers / footers
343 if (!m_bBufferSectionHeaders)
345 m_rExport.Strm().WriteOString(m_aSectionHeaders);
346 m_aSectionHeaders.setLength(0);
349 if (aNextIndex.GetNode().IsTextNode())
351 const SwTextNode* pTextNode = static_cast<SwTextNode*>(&aNextIndex.GetNode());
352 m_rExport.OutputSectionBreaks(pTextNode->GetpSwAttrSet(), *pTextNode);
353 // Save the current page description for now, so later we will be able to access the previous one.
354 m_pPrevPageDesc = pTextNode->FindPageDesc();
356 else if (aNextIndex.GetNode().IsTableNode())
358 const SwTableNode* pTableNode = static_cast<SwTableNode*>(&aNextIndex.GetNode());
359 const SwFrameFormat* pFormat = pTableNode->GetTable().GetFrameFormat();
360 m_rExport.OutputSectionBreaks(&(pFormat->GetAttrSet()), *pTableNode);
362 m_bBufferSectionBreaks = false;
364 else if (rNode.IsEndNode())
366 // End of something: make sure that it's the end of a table.
367 assert(rNode.StartOfSectionNode()->IsTableNode());
368 if (aNextIndex.GetNode().IsTextNode())
370 // Handle section break between a table and a text node following it.
371 const SwTextNode* pTextNode = aNextIndex.GetNode().GetTextNode();
372 m_rExport.OutputSectionBreaks(pTextNode->GetpSwAttrSet(), *pTextNode);
377 void RtfAttributeOutput::StartParagraphProperties()
379 OStringBuffer aPar;
380 if (!m_rExport.GetRTFFlySyntax())
382 aPar.append(OOO_STRING_SVTOOLS_RTF_PARD OOO_STRING_SVTOOLS_RTF_PLAIN " ");
384 if (!m_bBufferSectionHeaders)
385 m_rExport.Strm().WriteOString(aPar);
386 else
387 m_aSectionHeaders.append(aPar);
390 void RtfAttributeOutput::EndParagraphProperties(
391 const SfxItemSet& /*rParagraphMarkerProperties*/, const SwRedlineData* /*pRedlineData*/,
392 const SwRedlineData* /*pRedlineParagraphMarkerDeleted*/,
393 const SwRedlineData* /*pRedlineParagraphMarkerInserted*/)
395 // Do not call MoveCharacterProperties(),
396 // Otherwise associate properties in the paragraph style are ruined.
397 const OString aProperties = m_aStyles.makeStringAndClear();
398 m_rExport.Strm().WriteOString(aProperties);
401 void RtfAttributeOutput::StartRun(const SwRedlineData* pRedlineData, sal_Int32 /*nPos*/,
402 bool bSingleEmptyRun)
404 SAL_INFO("sw.rtf", __func__ << ", bSingleEmptyRun: " << bSingleEmptyRun);
406 m_bInRun = true;
407 m_bSingleEmptyRun = bSingleEmptyRun;
408 if (!m_bSingleEmptyRun)
409 m_aRun->append('{');
411 // if there is some redlining in the document, output it
412 Redline(pRedlineData);
414 OSL_ENSURE(m_aRunText.getLength() == 0, "m_aRunText is not empty");
417 void RtfAttributeOutput::EndRun(const SwTextNode* /*pNode*/, sal_Int32 /*nPos*/, sal_Int32 /*nLen*/,
418 bool /*bLastRun*/)
420 m_aRun->append(SAL_NEWLINE_STRING);
421 m_aRun.appendAndClear(m_aRunText);
423 if (m_bInRuby)
425 m_aRun->append(")}}{" OOO_STRING_SVTOOLS_RTF_FLDRSLT " {}}}");
426 m_bInRuby = false;
429 if (!m_bSingleEmptyRun && m_bInRun)
430 m_aRun->append('}');
431 m_bInRun = false;
434 void RtfAttributeOutput::StartRunProperties()
436 OSL_ENSURE(m_aStyles.getLength() == 0, "m_aStyles is not empty");
439 void RtfAttributeOutput::EndRunProperties(const SwRedlineData* /*pRedlineData*/)
441 const OString aProperties = MoveCharacterProperties(true);
442 m_aRun->append(aProperties);
445 OString RtfAttributeOutput::MoveCharacterProperties(bool aAutoWriteRtlLtr)
447 const OString aAssocHich = m_aStylesAssocHich.makeStringAndClear();
448 const OString aAssocDbch = m_aStylesAssocDbch.makeStringAndClear();
449 const OString aAssocRtlch = m_aStylesAssocRtlch.makeStringAndClear();
450 const OString aAssocLtrch = m_aStylesAssocLtrch.makeStringAndClear();
451 const OString aNormal = m_aStyles.makeStringAndClear();
452 OStringBuffer aBuf;
454 if (aAutoWriteRtlLtr && !m_bControlLtrRtl)
456 m_bControlLtrRtl = !aAssocRtlch.isEmpty();
457 m_bIsRTL = false;
458 m_nScript = i18n::ScriptType::LATIN;
461 if (m_bIsRTL)
463 if (!aAssocRtlch.isEmpty())
465 aBuf.append(OOO_STRING_SVTOOLS_RTF_LTRCH + aAssocLtrch
466 + " " OOO_STRING_SVTOOLS_RTF_RTLCH + aAssocRtlch);
469 else
471 if (!aAssocRtlch.isEmpty())
473 aBuf.append(OOO_STRING_SVTOOLS_RTF_RTLCH + aAssocRtlch
474 + " " OOO_STRING_SVTOOLS_RTF_LTRCH + aAssocLtrch);
476 if (!aAssocHich.isEmpty())
478 aBuf.append(OOO_STRING_SVTOOLS_RTF_HICH + aAssocHich);
480 if (!aNormal.isEmpty())
482 aBuf.append(OOO_STRING_SVTOOLS_RTF_LOCH + aNormal);
484 if (!aAssocDbch.isEmpty())
486 aBuf.append(OOO_STRING_SVTOOLS_RTF_DBCH + aAssocDbch);
490 if (m_bControlLtrRtl)
492 m_bControlLtrRtl = false;
494 switch (m_nScript)
496 case i18n::ScriptType::LATIN:
497 aBuf.append(OOO_STRING_SVTOOLS_RTF_LOCH);
498 break;
499 case i18n::ScriptType::ASIAN:
500 aBuf.append(OOO_STRING_SVTOOLS_RTF_DBCH);
501 break;
502 case i18n::ScriptType::COMPLEX:
503 /* noop */
504 default:
505 /* should not happen? */
506 break;
510 return aBuf.makeStringAndClear();
513 void RtfAttributeOutput::RunText(const OUString& rText, rtl_TextEncoding /*eCharSet*/,
514 const OUString& /*rSymbolFont*/)
516 SAL_INFO("sw.rtf", __func__ << ", rText: " << rText);
517 RawText(rText, m_rExport.GetCurrentEncoding());
520 OStringBuffer& RtfAttributeOutput::RunText() { return m_aRunText.getLastBuffer(); }
522 void RtfAttributeOutput::RawText(const OUString& rText, rtl_TextEncoding eCharSet)
524 m_aRunText->append(msfilter::rtfutil::OutString(rText, eCharSet));
527 void RtfAttributeOutput::StartRuby(const SwTextNode& rNode, sal_Int32 /*nPos*/,
528 const SwFormatRuby& rRuby)
530 WW8Ruby aWW8Ruby(rNode, rRuby, GetExport());
531 OUString aStr = FieldString(ww::eEQ) + "\\* jc" + OUString::number(aWW8Ruby.GetJC())
532 + " \\* \"Font:" + aWW8Ruby.GetFontFamily() + "\" \\* hps"
533 + OUString::number((aWW8Ruby.GetRubyHeight() + 5) / 10) + " \\o";
534 if (aWW8Ruby.GetDirective())
536 aStr += "\\a" + OUStringChar(aWW8Ruby.GetDirective());
538 aStr += "(\\s\\up " + OUString::number((aWW8Ruby.GetBaseHeight() + 10) / 20 - 1) + "(";
539 m_rExport.OutputField(nullptr, ww::eEQ, aStr, FieldFlags::Start | FieldFlags::CmdStart);
540 aStr = rRuby.GetText() + "),";
541 m_rExport.OutputField(nullptr, ww::eEQ, aStr, FieldFlags::NONE);
542 m_bInRuby = true;
545 void RtfAttributeOutput::EndRuby(const SwTextNode& /*rNode*/, sal_Int32 /*nPos*/) {}
547 bool RtfAttributeOutput::StartURL(const OUString& rUrl, const OUString& rTarget)
549 m_aURLs.push(rUrl);
550 // Ignore hyperlink without a URL.
551 if (!rUrl.isEmpty())
553 m_aRun->append('{');
554 m_aRun->append(OOO_STRING_SVTOOLS_RTF_FIELD);
555 m_aRun->append('{');
556 m_aRun->append(OOO_STRING_SVTOOLS_RTF_IGNORE);
557 m_aRun->append(OOO_STRING_SVTOOLS_RTF_FLDINST);
558 m_aRun->append(" HYPERLINK ");
560 m_aRun->append("\"");
561 m_aRun->append(msfilter::rtfutil::OutString(rUrl, m_rExport.GetCurrentEncoding()));
562 m_aRun->append("\" ");
564 if (!rTarget.isEmpty())
566 m_aRun->append("\\\\t \"");
567 m_aRun->append(msfilter::rtfutil::OutString(rTarget, m_rExport.GetCurrentEncoding()));
568 m_aRun->append("\" ");
571 m_aRun->append("}");
572 m_aRun->append("{" OOO_STRING_SVTOOLS_RTF_FLDRSLT " {");
574 return true;
577 bool RtfAttributeOutput::EndURL(bool const isAtEndOfParagraph)
579 if (m_aURLs.empty())
581 return true;
584 const OUString& rURL = m_aURLs.top();
585 if (!rURL.isEmpty())
587 // UGLY: usually EndRun is called earlier, but there is an extra
588 // call to OutAttrWithRange() when at the end of the paragraph,
589 // so in that special case the output needs to be appended to the
590 // new run's text instead of the previous run
591 if (isAtEndOfParagraph)
593 // close the fldrslt group
594 m_aRunText->append("}}");
595 // close the field group
596 m_aRunText->append('}');
598 else
600 // close the fldrslt group
601 m_aRun->append("}}");
602 // close the field group
603 m_aRun->append('}');
606 m_aURLs.pop();
607 return true;
610 void RtfAttributeOutput::FieldVanish(const OUString& /*rText*/, ww::eField /*eType*/,
611 OUString const* /*pBookmarkName*/)
613 SAL_INFO("sw.rtf", "TODO: " << __func__);
616 void RtfAttributeOutput::Redline(const SwRedlineData* pRedline)
618 if (!pRedline)
619 return;
621 if (pRedline->GetType() == RedlineType::Insert)
623 m_aRun->append(OOO_STRING_SVTOOLS_RTF_REVISED);
624 m_aRun->append(OOO_STRING_SVTOOLS_RTF_REVAUTH);
625 m_aRun->append(static_cast<sal_Int32>(
626 m_rExport.GetRedline(SW_MOD()->GetRedlineAuthor(pRedline->GetAuthor()))));
627 m_aRun->append(OOO_STRING_SVTOOLS_RTF_REVDTTM);
629 else if (pRedline->GetType() == RedlineType::Delete)
631 m_aRun->append(OOO_STRING_SVTOOLS_RTF_DELETED);
632 m_aRun->append(OOO_STRING_SVTOOLS_RTF_REVAUTHDEL);
633 m_aRun->append(static_cast<sal_Int32>(
634 m_rExport.GetRedline(SW_MOD()->GetRedlineAuthor(pRedline->GetAuthor()))));
635 m_aRun->append(OOO_STRING_SVTOOLS_RTF_REVDTTMDEL);
637 m_aRun->append(static_cast<sal_Int32>(sw::ms::DateTime2DTTM(pRedline->GetTimeStamp())));
638 m_aRun->append(' ');
641 void RtfAttributeOutput::FormatDrop(const SwTextNode& /*rNode*/,
642 const SwFormatDrop& /*rSwFormatDrop*/, sal_uInt16 /*nStyle*/,
643 ww8::WW8TableNodeInfo::Pointer_t /*pTextNodeInfo*/,
644 ww8::WW8TableNodeInfoInner::Pointer_t /*pTextNodeInfoInner*/)
646 SAL_INFO("sw.rtf", "TODO: " << __func__);
649 void RtfAttributeOutput::ParagraphStyle(sal_uInt16 nStyle)
651 OString* pStyle = m_rExport.GetStyle(nStyle);
652 OStringBuffer aStyle(OOO_STRING_SVTOOLS_RTF_S
653 + OString::number(static_cast<sal_Int32>(nStyle)));
654 if (pStyle)
655 aStyle.append(*pStyle);
656 if (!m_bBufferSectionHeaders)
657 m_rExport.Strm().WriteOString(aStyle);
658 else
659 m_aSectionHeaders.append(aStyle);
662 void RtfAttributeOutput::TableInfoCell(
663 ww8::WW8TableNodeInfoInner::Pointer_t /*pTableTextNodeInfoInner*/)
665 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_INTBL);
666 if (m_nTableDepth > 1)
668 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ITAP);
669 m_aStyles.append(static_cast<sal_Int32>(m_nTableDepth));
671 m_bWroteCellInfo = true;
674 void RtfAttributeOutput::TableInfoRow(ww8::WW8TableNodeInfoInner::Pointer_t /*pTableTextNodeInfo*/)
676 /* noop */
679 void RtfAttributeOutput::TablePositioning(SwFrameFormat* pFlyFormat)
681 if (!pFlyFormat || !pFlyFormat->GetFlySplit().GetValue())
683 return;
686 switch (pFlyFormat->GetVertOrient().GetRelationOrient())
688 case text::RelOrientation::PAGE_PRINT_AREA:
689 // relative to margin
690 m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TPVMRG);
691 break;
692 case text::RelOrientation::PAGE_FRAME:
693 // relative to page
694 m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TPVPG);
695 break;
696 default:
697 // text::RelOrientation::FRAME
698 // relative to text
699 m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TPVPARA);
700 break;
703 switch (pFlyFormat->GetHoriOrient().GetRelationOrient())
705 case text::RelOrientation::FRAME:
706 // relative to column
707 m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TPHCOL);
708 break;
709 case text::RelOrientation::PAGE_PRINT_AREA:
710 // relative to margin
711 m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TPHMRG);
712 break;
713 default:
714 // text::RelOrientation::PAGE_FRAME
715 // relative to page
716 m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TPHPG);
717 break;
720 // Similar to RtfAttributeOutput::FormatHorizOrientation(), but for tables.
721 switch (pFlyFormat->GetHoriOrient().GetHoriOrient())
723 case text::HoriOrientation::LEFT:
724 // left
725 m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TPOSXL);
726 break;
727 case text::HoriOrientation::CENTER:
728 // centered
729 m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TPOSXC);
730 break;
731 case text::HoriOrientation::RIGHT:
732 // right
733 m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TPOSXR);
734 break;
735 default:
736 SwTwips nTPosX = pFlyFormat->GetHoriOrient().GetPos();
737 m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TPOSX);
738 m_aRowDefs.append(static_cast<sal_Int32>(nTPosX));
739 break;
742 // Similar to RtfAttributeOutput::FormatVertOrientation(), but for tables.
743 switch (pFlyFormat->GetVertOrient().GetVertOrient())
745 case text::VertOrientation::TOP:
746 // up
747 m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TPOSYT);
748 break;
749 case text::VertOrientation::CENTER:
750 // centered
751 m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TPOSYC);
752 break;
753 case text::VertOrientation::BOTTOM:
754 // down
755 m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TPOSYB);
756 break;
757 default:
758 SwTwips nTPosY = pFlyFormat->GetVertOrient().GetPos();
759 m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TPOSY);
760 m_aRowDefs.append(static_cast<sal_Int32>(nTPosY));
761 break;
764 // Similar to RtfAttributeOutput::FormatULSpace(), but for tables.
765 sal_uInt16 nTdfrmtxtTop = pFlyFormat->GetULSpace().GetUpper();
766 m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TDFRMTXTTOP);
767 m_aRowDefs.append(static_cast<sal_Int32>(nTdfrmtxtTop));
768 sal_uInt16 nTdfrmtxtBottom = pFlyFormat->GetULSpace().GetLower();
769 m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TDFRMTXTBOTTOM);
770 m_aRowDefs.append(static_cast<sal_Int32>(nTdfrmtxtBottom));
772 // Similar to RtfAttributeOutput::FormatLRSpace(), but for tables.
773 sal_uInt16 nTdfrmtxtLeft = pFlyFormat->GetLRSpace().GetLeft();
774 m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TDFRMTXTLEFT);
775 m_aRowDefs.append(static_cast<sal_Int32>(nTdfrmtxtLeft));
776 sal_uInt16 nTdfrmtxtRight = pFlyFormat->GetLRSpace().GetRight();
777 m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TDFRMTXTRIGHT);
778 m_aRowDefs.append(static_cast<sal_Int32>(nTdfrmtxtRight));
780 if (!pFlyFormat->GetWrapInfluenceOnObjPos().GetAllowOverlap())
782 // Allowing overlap is the default in both Writer and in RTF.
783 m_aRowDefs.append(LO_STRING_SVTOOLS_RTF_TABSNOOVRLP);
784 m_aRowDefs.append(static_cast<sal_Int32>(1));
788 void RtfAttributeOutput::TableDefinition(
789 ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)
791 InitTableHelper(pTableTextNodeInfoInner);
793 const SwTable* pTable = pTableTextNodeInfoInner->getTable();
794 SwFrameFormat* pFormat = pTable->GetFrameFormat();
796 m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_TROWD);
797 TableOrientation(pTableTextNodeInfoInner);
798 TableBidi(pTableTextNodeInfoInner);
799 TableHeight(pTableTextNodeInfoInner);
800 TableCanSplit(pTableTextNodeInfoInner);
802 // Write table positioning properties in case this is a floating table.
803 TablePositioning(pTable->GetTableNode()->GetFlyFormat());
805 // Cell margins
806 const SvxBoxItem& rBox = pFormat->GetBox();
807 static const SvxBoxItemLine aBorders[] = { SvxBoxItemLine::TOP, SvxBoxItemLine::LEFT,
808 SvxBoxItemLine::BOTTOM, SvxBoxItemLine::RIGHT };
810 static const char* aRowPadNames[]
811 = { OOO_STRING_SVTOOLS_RTF_TRPADDT, OOO_STRING_SVTOOLS_RTF_TRPADDL,
812 OOO_STRING_SVTOOLS_RTF_TRPADDB, OOO_STRING_SVTOOLS_RTF_TRPADDR };
814 static const char* aRowPadUnits[]
815 = { OOO_STRING_SVTOOLS_RTF_TRPADDFT, OOO_STRING_SVTOOLS_RTF_TRPADDFL,
816 OOO_STRING_SVTOOLS_RTF_TRPADDFB, OOO_STRING_SVTOOLS_RTF_TRPADDFR };
818 for (int i = 0; i < 4; ++i)
820 m_aRowDefs.append(aRowPadUnits[i]);
821 m_aRowDefs.append(sal_Int32(3));
822 m_aRowDefs.append(aRowPadNames[i]);
823 m_aRowDefs.append(static_cast<sal_Int32>(rBox.GetDistance(aBorders[i])));
826 // The cell-dependent properties
827 const double fWidthRatio = m_pTableWrt->GetAbsWidthRatio();
828 const SwWriteTableRows& aRows = m_pTableWrt->GetRows();
829 sal_uInt32 nRow = pTableTextNodeInfoInner->getRow();
830 if (nRow >= aRows.size())
832 SAL_WARN("sw.ww8", "RtfAttributeOutput::TableDefinition: out of range row: " << nRow);
833 return;
835 SwWriteTableRow* pRow = aRows[nRow].get();
836 SwTwips nSz = 0;
838 // Not using m_nTableDepth, which is not yet incremented here.
839 sal_uInt32 nCurrentDepth = pTableTextNodeInfoInner->getDepth();
840 m_aCells[nCurrentDepth] = pRow->GetCells().size();
841 for (sal_uInt32 i = 0; i < m_aCells[nCurrentDepth]; i++)
843 const SwWriteTableCell* const pCell = pRow->GetCells()[i].get();
844 const SwFrameFormat* pCellFormat = pCell->GetBox()->GetFrameFormat();
846 pTableTextNodeInfoInner->setCell(i);
847 TableCellProperties(pTableTextNodeInfoInner);
849 // Right boundary: this can't be in TableCellProperties as the old
850 // value of nSz is needed.
851 nSz += pCellFormat->GetFrameSize().GetWidth();
852 m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CELLX);
853 m_aRowDefs.append(static_cast<sal_Int32>(pFormat->GetLRSpace().GetLeft()
854 + rtl::math::round(nSz * fWidthRatio)));
858 void RtfAttributeOutput::TableDefaultBorders(
859 ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)
862 * The function name is a bit misleading: given that we write borders
863 * before each row, we just have borders, not default ones. Additionally,
864 * this function actually writes borders for a specific cell only and is
865 * called for each cell.
868 const SwWriteTableRows& aRows = m_pTableWrt->GetRows();
869 SwWriteTableRow* pRow = aRows[pTableTextNodeInfoInner->getRow()].get();
870 const SwWriteTableCell* const pCell
871 = pRow->GetCells()[pTableTextNodeInfoInner->getCell()].get();
872 const SwFrameFormat* pCellFormat = pCell->GetBox()->GetFrameFormat();
873 const SvxBoxItem* pItem = pCellFormat->GetAttrSet().GetItemIfSet(RES_BOX);
874 if (!pItem)
875 return;
877 auto& rBox = *pItem;
878 static const SvxBoxItemLine aBorders[] = { SvxBoxItemLine::TOP, SvxBoxItemLine::LEFT,
879 SvxBoxItemLine::BOTTOM, SvxBoxItemLine::RIGHT };
880 static const char* aBorderNames[]
881 = { OOO_STRING_SVTOOLS_RTF_CLBRDRT, OOO_STRING_SVTOOLS_RTF_CLBRDRL,
882 OOO_STRING_SVTOOLS_RTF_CLBRDRB, OOO_STRING_SVTOOLS_RTF_CLBRDRR };
883 //Yes left and top are swapped with each other for cell padding! Because
884 //that's what the thundering annoying rtf export/import word xp does.
885 static const char* aCellPadNames[]
886 = { OOO_STRING_SVTOOLS_RTF_CLPADL, OOO_STRING_SVTOOLS_RTF_CLPADT,
887 OOO_STRING_SVTOOLS_RTF_CLPADB, OOO_STRING_SVTOOLS_RTF_CLPADR };
888 static const char* aCellPadUnits[]
889 = { OOO_STRING_SVTOOLS_RTF_CLPADFL, OOO_STRING_SVTOOLS_RTF_CLPADFT,
890 OOO_STRING_SVTOOLS_RTF_CLPADFB, OOO_STRING_SVTOOLS_RTF_CLPADFR };
891 for (int i = 0; i < 4; ++i)
893 if (const editeng::SvxBorderLine* pLn = rBox.GetLine(aBorders[i]))
894 m_aRowDefs.append(OutTBLBorderLine(m_rExport, pLn, aBorderNames[i]));
895 if (rBox.GetDistance(aBorders[i]))
897 m_aRowDefs.append(aCellPadUnits[i]);
898 m_aRowDefs.append(sal_Int32(3));
899 m_aRowDefs.append(aCellPadNames[i]);
900 m_aRowDefs.append(static_cast<sal_Int32>(rBox.GetDistance(aBorders[i])));
905 void RtfAttributeOutput::TableBackgrounds(
906 ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)
908 const SwTable* pTable = pTableTextNodeInfoInner->getTable();
909 const SwTableBox* pTableBox = pTableTextNodeInfoInner->getTableBox();
910 const SwTableLine* pTableLine = pTableBox->GetUpper();
912 Color aColor = COL_AUTO;
913 auto pTableColorProp
914 = pTable->GetFrameFormat()->GetAttrSet().GetItem<SvxBrushItem>(RES_BACKGROUND);
915 if (pTableColorProp)
916 aColor = pTableColorProp->GetColor();
918 auto pRowColorProp
919 = pTableLine->GetFrameFormat()->GetAttrSet().GetItem<SvxBrushItem>(RES_BACKGROUND);
920 if (pRowColorProp && pRowColorProp->GetColor() != COL_AUTO)
921 aColor = pRowColorProp->GetColor();
923 const SwWriteTableRows& aRows = m_pTableWrt->GetRows();
924 SwWriteTableRow* pRow = aRows[pTableTextNodeInfoInner->getRow()].get();
925 const SwWriteTableCell* const pCell
926 = pRow->GetCells()[pTableTextNodeInfoInner->getCell()].get();
927 const SwFrameFormat* pCellFormat = pCell->GetBox()->GetFrameFormat();
928 if (const SvxBrushItem* pBrushItem = pCellFormat->GetAttrSet().GetItemIfSet(RES_BACKGROUND))
930 if (pBrushItem->GetColor() != COL_AUTO)
931 aColor = pBrushItem->GetColor();
934 if (!aColor.IsTransparent())
936 m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CLCBPAT);
937 m_aRowDefs.append(static_cast<sal_Int32>(m_rExport.GetColor(aColor)));
941 void RtfAttributeOutput::TableRowRedline(
942 ww8::WW8TableNodeInfoInner::Pointer_t /*pTableTextNodeInfoInner*/)
946 void RtfAttributeOutput::TableCellRedline(
947 ww8::WW8TableNodeInfoInner::Pointer_t /*pTableTextNodeInfoInner*/)
951 void RtfAttributeOutput::TableHeight(ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)
953 const SwTableBox* pTabBox = pTableTextNodeInfoInner->getTableBox();
954 const SwTableLine* pTabLine = pTabBox->GetUpper();
955 const SwFrameFormat* pLineFormat = pTabLine->GetFrameFormat();
956 const SwFormatFrameSize& rLSz = pLineFormat->GetFrameSize();
958 if (!(SwFrameSize::Variable != rLSz.GetHeightSizeType() && rLSz.GetHeight()))
959 return;
961 sal_Int32 nHeight = 0;
963 switch (rLSz.GetHeightSizeType())
965 case SwFrameSize::Fixed:
966 nHeight = -rLSz.GetHeight();
967 break;
968 case SwFrameSize::Minimum:
969 nHeight = rLSz.GetHeight();
970 break;
971 default:
972 break;
975 if (nHeight)
977 m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_TRRH);
978 m_aRowDefs.append(nHeight);
982 void RtfAttributeOutput::TableCanSplit(
983 ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)
985 const SwTableBox* pTabBox = pTableTextNodeInfoInner->getTableBox();
986 const SwTableLine* pTabLine = pTabBox->GetUpper();
987 const SwFrameFormat* pLineFormat = pTabLine->GetFrameFormat();
988 const SwFormatRowSplit& rSplittable = pLineFormat->GetRowSplit();
990 // The rtf default is to allow a row to break
991 if (!rSplittable.GetValue())
992 m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_TRKEEP);
995 void RtfAttributeOutput::TableBidi(ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)
997 const SwTable* pTable = pTableTextNodeInfoInner->getTable();
998 const SwFrameFormat* pFrameFormat = pTable->GetFrameFormat();
1000 if (m_rExport.TrueFrameDirection(*pFrameFormat) != SvxFrameDirection::Horizontal_RL_TB)
1001 m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_LTRROW);
1002 else
1003 m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_RTLROW);
1006 void RtfAttributeOutput::TableVerticalCell(
1007 ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)
1009 const SwWriteTableRows& aRows = m_pTableWrt->GetRows();
1010 SwWriteTableRow* pRow = aRows[pTableTextNodeInfoInner->getRow()].get();
1011 const SwWriteTableCell* const pCell
1012 = pRow->GetCells()[pTableTextNodeInfoInner->getCell()].get();
1013 const SwFrameFormat* pCellFormat = pCell->GetBox()->GetFrameFormat();
1015 // Text direction.
1016 if (SvxFrameDirection::Vertical_RL_TB == m_rExport.TrueFrameDirection(*pCellFormat))
1017 m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CLTXTBRL);
1018 else if (SvxFrameDirection::Vertical_LR_BT == m_rExport.TrueFrameDirection(*pCellFormat))
1019 m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CLTXBTLR);
1021 // vertical merges
1022 if (pCell->GetRowSpan() > 1)
1023 m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CLVMGF);
1024 else if (pCell->GetRowSpan() == 0)
1025 m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CLVMRG);
1027 // vertical alignment
1028 const SwFormatVertOrient* pVertOrientItem
1029 = pCellFormat->GetAttrSet().GetItemIfSet(RES_VERT_ORIENT);
1030 if (!pVertOrientItem)
1031 return;
1033 switch (pVertOrientItem->GetVertOrient())
1035 case text::VertOrientation::CENTER:
1036 m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CLVERTALC);
1037 break;
1038 case text::VertOrientation::BOTTOM:
1039 m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CLVERTALB);
1040 break;
1041 default:
1042 m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CLVERTALT);
1043 break;
1047 void RtfAttributeOutput::TableNodeInfoInner(ww8::WW8TableNodeInfoInner::Pointer_t pNodeInfoInner)
1049 // This is called when the nested table ends in a cell, and there's no
1050 // paragraph behind that; so we must check for the ends of cell, rows,
1051 // and tables
1052 FinishTableRowCell(pNodeInfoInner);
1055 void RtfAttributeOutput::TableOrientation(
1056 ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner)
1058 const SwTable* pTable = pTableTextNodeInfoInner->getTable();
1059 SwFrameFormat* pFormat = pTable->GetFrameFormat();
1061 OStringBuffer aTableAdjust(OOO_STRING_SVTOOLS_RTF_TRQL);
1062 switch (pFormat->GetHoriOrient().GetHoriOrient())
1064 case text::HoriOrientation::CENTER:
1065 aTableAdjust.setLength(0);
1066 aTableAdjust.append(OOO_STRING_SVTOOLS_RTF_TRQC);
1067 break;
1068 case text::HoriOrientation::RIGHT:
1069 aTableAdjust.setLength(0);
1070 aTableAdjust.append(OOO_STRING_SVTOOLS_RTF_TRQR);
1071 break;
1072 case text::HoriOrientation::NONE:
1073 case text::HoriOrientation::LEFT_AND_WIDTH:
1074 aTableAdjust.append(OOO_STRING_SVTOOLS_RTF_TRLEFT);
1075 aTableAdjust.append(static_cast<sal_Int32>(pFormat->GetLRSpace().GetLeft()));
1076 break;
1077 default:
1078 break;
1081 m_aRowDefs.append(aTableAdjust);
1084 void RtfAttributeOutput::TableSpacing(
1085 ww8::WW8TableNodeInfoInner::Pointer_t /*pTableTextNodeInfoInner*/)
1087 SAL_INFO("sw.rtf", "TODO: " << __func__);
1090 void RtfAttributeOutput::TableRowEnd(sal_uInt32 /*nDepth*/) { /* noop, see EndTableRow() */}
1093 * Our private table methods.
1096 void RtfAttributeOutput::InitTableHelper(
1097 const ww8::WW8TableNodeInfoInner::Pointer_t& pTableTextNodeInfoInner)
1099 const SwTable* pTable = pTableTextNodeInfoInner->getTable();
1100 if (m_pTableWrt && pTable == m_pTableWrt->GetTable())
1101 return;
1103 tools::Long nPageSize = 0;
1104 bool bRelBoxSize = false;
1106 // Create the SwWriteTable instance to use col spans
1107 GetTablePageSize(pTableTextNodeInfoInner.get(), nPageSize, bRelBoxSize);
1109 const SwFrameFormat* pFormat = pTable->GetFrameFormat();
1110 const sal_uInt32 nTableSz = pFormat->GetFrameSize().GetWidth();
1112 const SwHTMLTableLayout* pLayout = pTable->GetHTMLTableLayout();
1113 if (pLayout && pLayout->IsExportable())
1114 m_pTableWrt = std::make_unique<SwWriteTable>(pTable, pLayout);
1115 else
1116 m_pTableWrt = std::make_unique<SwWriteTable>(pTable, pTable->GetTabLines(), nPageSize,
1117 nTableSz, false);
1120 void RtfAttributeOutput::StartTable()
1122 // To trigger calling InitTableHelper()
1123 m_pTableWrt.reset();
1126 void RtfAttributeOutput::StartTableRow(
1127 const ww8::WW8TableNodeInfoInner::Pointer_t& pTableTextNodeInfoInner)
1129 sal_uInt32 nCurrentDepth = pTableTextNodeInfoInner->getDepth();
1130 SAL_INFO("sw.rtf", __func__ << ", (depth is " << nCurrentDepth << ")");
1131 m_bTableRowEnded = false;
1133 TableDefinition(pTableTextNodeInfoInner);
1135 if (!m_bLastTable)
1136 m_aTables.push_back(m_aRowDefs.makeStringAndClear());
1138 // We'll write the table definition for nested tables later
1139 if (nCurrentDepth > 1)
1140 return;
1141 // Empty the previous row closing buffer before starting the new one,
1142 // necessary for subtables.
1143 m_rExport.Strm().WriteOString(m_aAfterRuns);
1144 m_aAfterRuns.setLength(0);
1145 m_rExport.Strm().WriteOString(m_aRowDefs);
1146 m_aRowDefs.setLength(0);
1149 void RtfAttributeOutput::StartTableCell() { m_bTableCellOpen = true; }
1151 void RtfAttributeOutput::TableCellProperties(
1152 const ww8::WW8TableNodeInfoInner::Pointer_t& pTableTextNodeInfoInner)
1154 TableDefaultBorders(pTableTextNodeInfoInner);
1155 TableBackgrounds(pTableTextNodeInfoInner);
1156 TableVerticalCell(pTableTextNodeInfoInner);
1159 void RtfAttributeOutput::EndTableCell()
1161 SAL_INFO("sw.rtf", __func__ << ", (depth is " << m_nTableDepth << ")");
1163 if (!m_bWroteCellInfo)
1165 m_aAfterRuns.append(OOO_STRING_SVTOOLS_RTF_INTBL);
1166 m_aAfterRuns.append(OOO_STRING_SVTOOLS_RTF_ITAP);
1167 m_aAfterRuns.append(static_cast<sal_Int32>(m_nTableDepth));
1169 if (m_nTableDepth > 1)
1170 m_aAfterRuns.append(OOO_STRING_SVTOOLS_RTF_NESTCELL);
1171 else
1172 m_aAfterRuns.append(OOO_STRING_SVTOOLS_RTF_CELL);
1174 m_bTableCellOpen = false;
1175 m_bTableAfterCell = true;
1176 m_bWroteCellInfo = false;
1177 if (m_aCells[m_nTableDepth] > 0)
1178 m_aCells[m_nTableDepth]--;
1181 void RtfAttributeOutput::EndTableRow()
1183 SAL_INFO("sw.rtf", __func__ << ", (depth is " << m_nTableDepth << ")");
1185 if (m_nTableDepth > 1)
1187 m_aAfterRuns.append(
1188 "{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_NESTTABLEPROPRS);
1189 if (!m_aRowDefs.isEmpty())
1191 m_aAfterRuns.append(m_aRowDefs);
1192 m_aRowDefs.setLength(0);
1194 else if (!m_aTables.empty())
1196 m_aAfterRuns.append(m_aTables.back());
1197 m_aTables.pop_back();
1199 m_aAfterRuns.append(OOO_STRING_SVTOOLS_RTF_NESTROW
1201 "{" OOO_STRING_SVTOOLS_RTF_NONESTTABLES OOO_STRING_SVTOOLS_RTF_PAR "}");
1203 else
1205 if (!m_aTables.empty())
1207 m_aAfterRuns.append(m_aTables.back());
1208 m_aTables.pop_back();
1210 // Make sure that the first word of the next paragraph is not merged with the last control
1211 // word of this table row, happens with floating tables.
1212 m_aAfterRuns.append(OOO_STRING_SVTOOLS_RTF_ROW OOO_STRING_SVTOOLS_RTF_PARD " ");
1214 m_bTableRowEnded = true;
1217 void RtfAttributeOutput::EndTable()
1219 if (m_nTableDepth > 0)
1221 m_nTableDepth--;
1222 m_pTableWrt.reset();
1225 // We closed the table; if it is a nested table, the cell that contains it
1226 // still continues
1227 m_bTableCellOpen = true;
1229 // Cleans the table helper
1230 m_pTableWrt.reset();
1233 void RtfAttributeOutput::FinishTableRowCell(const ww8::WW8TableNodeInfoInner::Pointer_t& pInner)
1235 if (!pInner)
1236 return;
1238 // Where are we in the table
1239 sal_uInt32 nRow = pInner->getRow();
1241 const SwTable* pTable = pInner->getTable();
1242 const SwTableLines& rLines = pTable->GetTabLines();
1243 sal_uInt16 nLinesCount = rLines.size();
1245 if (pInner->isEndOfCell())
1246 EndTableCell();
1248 // This is a line end
1249 if (pInner->isEndOfLine())
1250 EndTableRow();
1252 // This is the end of the table
1253 if (pInner->isEndOfLine() && (nRow + 1) == nLinesCount)
1254 EndTable();
1257 void RtfAttributeOutput::StartStyles()
1259 m_rExport.Strm()
1260 .WriteOString(SAL_NEWLINE_STRING)
1261 .WriteChar('{')
1262 .WriteOString(OOO_STRING_SVTOOLS_RTF_COLORTBL);
1263 m_rExport.OutColorTable();
1264 OSL_ENSURE(m_aStylesheet.getLength() == 0, "m_aStylesheet is not empty");
1265 m_aStylesheet.append(SAL_NEWLINE_STRING);
1266 m_aStylesheet.append('{');
1267 m_aStylesheet.append(OOO_STRING_SVTOOLS_RTF_STYLESHEET);
1270 void RtfAttributeOutput::EndStyles(sal_uInt16 /*nNumberOfStyles*/)
1272 m_rExport.Strm().WriteChar('}');
1273 m_rExport.Strm().WriteOString(m_aStylesheet);
1274 m_aStylesheet.setLength(0);
1275 m_rExport.Strm().WriteChar('}');
1278 void RtfAttributeOutput::DefaultStyle() { /* noop, the default style is always 0 in RTF */}
1280 void RtfAttributeOutput::StartStyle(const OUString& rName, StyleType eType, sal_uInt16 nBase,
1281 sal_uInt16 nNext, sal_uInt16 /*nLink*/, sal_uInt16 /*nWwId*/,
1282 sal_uInt16 nSlot, bool bAutoUpdate)
1284 SAL_INFO("sw.rtf", __func__ << ", rName = '" << rName << "'");
1286 m_aStylesheet.append('{');
1287 if (eType == STYLE_TYPE_PARA)
1288 m_aStylesheet.append(OOO_STRING_SVTOOLS_RTF_S);
1289 else
1290 m_aStylesheet.append(OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_CS);
1291 m_aStylesheet.append(static_cast<sal_Int32>(nSlot));
1293 if (nBase != 0x0FFF)
1295 m_aStylesheet.append(OOO_STRING_SVTOOLS_RTF_SBASEDON);
1296 m_aStylesheet.append(static_cast<sal_Int32>(nBase));
1299 m_aStylesheet.append(OOO_STRING_SVTOOLS_RTF_SNEXT);
1300 m_aStylesheet.append(static_cast<sal_Int32>(nNext));
1302 if (bAutoUpdate)
1303 m_aStylesheet.append(OOO_STRING_SVTOOLS_RTF_SAUTOUPD);
1305 m_rStyleName = rName;
1306 m_nStyleId = nSlot;
1309 void RtfAttributeOutput::EndStyle()
1311 OString aStyles = MoveCharacterProperties();
1312 m_rExport.InsStyle(m_nStyleId, aStyles);
1313 m_aStylesheet.append(aStyles);
1314 m_aStylesheet.append(' ');
1315 m_aStylesheet.append(
1316 msfilter::rtfutil::OutString(m_rStyleName, m_rExport.GetCurrentEncoding()));
1317 m_aStylesheet.append(";}");
1318 m_aStylesheet.append(SAL_NEWLINE_STRING);
1321 void RtfAttributeOutput::StartStyleProperties(bool /*bParProp*/, sal_uInt16 /*nStyle*/)
1323 /* noop */
1326 void RtfAttributeOutput::EndStyleProperties(bool /*bParProp*/) { /* noop */}
1328 void RtfAttributeOutput::OutlineNumbering(sal_uInt8 nLvl)
1330 if (nLvl >= WW8ListManager::nMaxLevel)
1331 nLvl = WW8ListManager::nMaxLevel - 1;
1333 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ILVL);
1334 m_aStyles.append(static_cast<sal_Int32>(nLvl));
1335 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_OUTLINELEVEL);
1336 m_aStyles.append(static_cast<sal_Int32>(nLvl));
1339 void RtfAttributeOutput::PageBreakBefore(bool bBreak)
1341 if (bBreak)
1343 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_PAGEBB);
1347 void RtfAttributeOutput::SectionBreak(sal_uInt8 nC, bool /*bBreakAfter*/,
1348 const WW8_SepInfo* pSectionInfo, bool /*bExtraPageBreak*/)
1350 switch (nC)
1352 case msword::ColumnBreak:
1353 m_nColBreakNeeded = true;
1354 break;
1355 case msword::PageBreak:
1356 if (pSectionInfo)
1357 m_rExport.SectionProperties(*pSectionInfo);
1358 break;
1362 void RtfAttributeOutput::StartSection()
1364 if (m_bIsBeforeFirstParagraph)
1365 return;
1367 m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_SECT OOO_STRING_SVTOOLS_RTF_SECTD);
1368 if (!m_bBufferSectionBreaks)
1370 m_rExport.Strm().WriteOString(m_aSectionBreaks);
1371 m_aSectionBreaks.setLength(0);
1375 void RtfAttributeOutput::EndSection()
1378 * noop, \sect must go to StartSection or Word won't notice multiple
1379 * columns...
1383 void RtfAttributeOutput::SectionFormProtection(bool bProtected)
1385 m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_SECTUNLOCKED);
1386 m_aSectionBreaks.append(static_cast<sal_Int32>(!bProtected));
1389 void RtfAttributeOutput::SectionLineNumbering(sal_uLong nRestartNo,
1390 const SwLineNumberInfo& rLnNumInfo)
1392 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_LINEMOD);
1393 m_rExport.Strm().WriteNumberAsString(rLnNumInfo.GetCountBy());
1394 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_LINEX);
1395 m_rExport.Strm().WriteNumberAsString(rLnNumInfo.GetPosFromLeft());
1396 if (!rLnNumInfo.IsRestartEachPage())
1397 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_LINECONT);
1399 if (nRestartNo > 0)
1401 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_LINESTARTS);
1402 m_rExport.Strm().WriteNumberAsString(nRestartNo);
1406 void RtfAttributeOutput::SectionTitlePage()
1409 * noop, handled in RtfExport::WriteHeaderFooter()
1413 void RtfAttributeOutput::SectionPageBorders(const SwFrameFormat* pFormat,
1414 const SwFrameFormat* /*pFirstPageFormat*/)
1416 const SvxBoxItem& rBox = pFormat->GetBox();
1417 editeng::WordBorderDistances aDistances;
1418 editeng::BorderDistancesToWord(rBox, m_aPageMargins, aDistances);
1420 if (aDistances.bFromEdge)
1422 sal_uInt16 nOpt = (1 << 5);
1423 m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_PGBRDROPT);
1424 m_aSectionBreaks.append(static_cast<sal_Int32>(nOpt));
1427 const editeng::SvxBorderLine* pLine = rBox.GetTop();
1428 if (pLine)
1429 m_aSectionBreaks.append(
1430 OutBorderLine(m_rExport, pLine, OOO_STRING_SVTOOLS_RTF_PGBRDRT, aDistances.nTop));
1431 pLine = rBox.GetBottom();
1432 if (pLine)
1433 m_aSectionBreaks.append(
1434 OutBorderLine(m_rExport, pLine, OOO_STRING_SVTOOLS_RTF_PGBRDRB, aDistances.nBottom));
1435 pLine = rBox.GetLeft();
1436 if (pLine)
1437 m_aSectionBreaks.append(
1438 OutBorderLine(m_rExport, pLine, OOO_STRING_SVTOOLS_RTF_PGBRDRL, aDistances.nLeft));
1439 pLine = rBox.GetRight();
1440 if (pLine)
1441 m_aSectionBreaks.append(
1442 OutBorderLine(m_rExport, pLine, OOO_STRING_SVTOOLS_RTF_PGBRDRR, aDistances.nRight));
1445 void RtfAttributeOutput::SectionBiDi(bool bBiDi)
1447 m_rExport.Strm().WriteOString(bBiDi ? OOO_STRING_SVTOOLS_RTF_RTLSECT
1448 : OOO_STRING_SVTOOLS_RTF_LTRSECT);
1451 void RtfAttributeOutput::SectionPageNumbering(sal_uInt16 nNumType,
1452 const ::std::optional<sal_uInt16>& oPageRestartNumber)
1454 if (oPageRestartNumber)
1456 m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_PGNSTARTS);
1457 m_aSectionBreaks.append(static_cast<sal_Int32>(*oPageRestartNumber));
1458 m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_PGNRESTART);
1461 const char* pStr = nullptr;
1462 switch (nNumType)
1464 case SVX_NUM_CHARS_UPPER_LETTER:
1465 case SVX_NUM_CHARS_UPPER_LETTER_N:
1466 pStr = OOO_STRING_SVTOOLS_RTF_PGNUCLTR;
1467 break;
1468 case SVX_NUM_CHARS_LOWER_LETTER:
1469 case SVX_NUM_CHARS_LOWER_LETTER_N:
1470 pStr = OOO_STRING_SVTOOLS_RTF_PGNLCLTR;
1471 break;
1472 case SVX_NUM_ROMAN_UPPER:
1473 pStr = OOO_STRING_SVTOOLS_RTF_PGNUCRM;
1474 break;
1475 case SVX_NUM_ROMAN_LOWER:
1476 pStr = OOO_STRING_SVTOOLS_RTF_PGNLCRM;
1477 break;
1479 case SVX_NUM_ARABIC:
1480 pStr = OOO_STRING_SVTOOLS_RTF_PGNDEC;
1481 break;
1483 if (pStr)
1484 m_aSectionBreaks.append(pStr);
1487 void RtfAttributeOutput::SectionType(sal_uInt8 nBreakCode)
1489 SAL_INFO("sw.rtf", __func__ << ", nBreakCode = " << int(nBreakCode));
1492 * break code: 0 No break, 1 New column
1493 * 2 New page, 3 Even page, 4 Odd page
1495 const char* sType = nullptr;
1496 switch (nBreakCode)
1498 case 1:
1499 sType = OOO_STRING_SVTOOLS_RTF_SBKCOL;
1500 break;
1501 case 2:
1502 sType = OOO_STRING_SVTOOLS_RTF_SBKPAGE;
1503 break;
1504 case 3:
1505 sType = OOO_STRING_SVTOOLS_RTF_SBKEVEN;
1506 break;
1507 case 4:
1508 sType = OOO_STRING_SVTOOLS_RTF_SBKODD;
1509 break;
1510 default:
1511 sType = OOO_STRING_SVTOOLS_RTF_SBKNONE;
1512 break;
1514 m_aSectionBreaks.append(sType);
1515 if (!m_bBufferSectionBreaks)
1517 m_rExport.Strm().WriteOString(m_aSectionBreaks);
1518 m_aSectionBreaks.setLength(0);
1522 void RtfAttributeOutput::SectFootnoteEndnotePr()
1524 WriteFootnoteEndnotePr(true, m_rExport.m_rDoc.GetFootnoteInfo());
1525 WriteFootnoteEndnotePr(false, m_rExport.m_rDoc.GetEndNoteInfo());
1528 void RtfAttributeOutput::WriteFootnoteEndnotePr(bool bFootnote, const SwEndNoteInfo& rInfo)
1530 const char* pOut = nullptr;
1532 if (bFootnote)
1534 switch (rInfo.m_aFormat.GetNumberingType())
1536 default:
1537 pOut = OOO_STRING_SVTOOLS_RTF_SFTNNAR;
1538 break;
1539 case SVX_NUM_CHARS_LOWER_LETTER:
1540 case SVX_NUM_CHARS_LOWER_LETTER_N:
1541 pOut = OOO_STRING_SVTOOLS_RTF_SFTNNALC;
1542 break;
1543 case SVX_NUM_CHARS_UPPER_LETTER:
1544 case SVX_NUM_CHARS_UPPER_LETTER_N:
1545 pOut = OOO_STRING_SVTOOLS_RTF_SFTNNAUC;
1546 break;
1547 case SVX_NUM_ROMAN_LOWER:
1548 pOut = OOO_STRING_SVTOOLS_RTF_SFTNNRLC;
1549 break;
1550 case SVX_NUM_ROMAN_UPPER:
1551 pOut = OOO_STRING_SVTOOLS_RTF_SFTNNRUC;
1552 break;
1553 case SVX_NUM_SYMBOL_CHICAGO:
1554 pOut = OOO_STRING_SVTOOLS_RTF_SFTNNCHI;
1555 break;
1558 else
1560 switch (rInfo.m_aFormat.GetNumberingType())
1562 default:
1563 pOut = OOO_STRING_SVTOOLS_RTF_SAFTNNAR;
1564 break;
1565 case SVX_NUM_CHARS_LOWER_LETTER:
1566 case SVX_NUM_CHARS_LOWER_LETTER_N:
1567 pOut = OOO_STRING_SVTOOLS_RTF_SAFTNNALC;
1568 break;
1569 case SVX_NUM_CHARS_UPPER_LETTER:
1570 case SVX_NUM_CHARS_UPPER_LETTER_N:
1571 pOut = OOO_STRING_SVTOOLS_RTF_SAFTNNAUC;
1572 break;
1573 case SVX_NUM_ROMAN_LOWER:
1574 pOut = OOO_STRING_SVTOOLS_RTF_SAFTNNRLC;
1575 break;
1576 case SVX_NUM_ROMAN_UPPER:
1577 pOut = OOO_STRING_SVTOOLS_RTF_SAFTNNRUC;
1578 break;
1579 case SVX_NUM_SYMBOL_CHICAGO:
1580 pOut = OOO_STRING_SVTOOLS_RTF_SAFTNNCHI;
1581 break;
1585 m_aSectionBreaks.append(pOut);
1587 if (!m_bBufferSectionBreaks)
1589 m_rExport.Strm().WriteOString(m_aSectionBreaks);
1590 m_aSectionBreaks.setLength(0);
1594 void RtfAttributeOutput::NumberingDefinition(sal_uInt16 nId, const SwNumRule& /*rRule*/)
1596 m_rExport.Strm().WriteChar('{').WriteOString(OOO_STRING_SVTOOLS_RTF_LISTOVERRIDE);
1597 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_LISTID);
1598 m_rExport.Strm().WriteNumberAsString(nId);
1599 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_LISTOVERRIDECOUNT).WriteChar('0');
1600 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_LS);
1601 m_rExport.Strm().WriteNumberAsString(nId).WriteChar('}');
1604 void RtfAttributeOutput::StartAbstractNumbering(sal_uInt16 nId)
1606 m_rExport.Strm()
1607 .WriteChar('{')
1608 .WriteOString(OOO_STRING_SVTOOLS_RTF_LIST)
1609 .WriteOString(OOO_STRING_SVTOOLS_RTF_LISTTEMPLATEID);
1610 m_rExport.Strm().WriteNumberAsString(nId);
1611 m_nListId = nId;
1614 void RtfAttributeOutput::EndAbstractNumbering()
1616 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_LISTID);
1617 m_rExport.Strm().WriteNumberAsString(m_nListId).WriteChar('}').WriteOString(SAL_NEWLINE_STRING);
1620 void RtfAttributeOutput::NumberingLevel(sal_uInt8 nLevel, sal_uInt16 nStart,
1621 sal_uInt16 nNumberingType, SvxAdjust eAdjust,
1622 const sal_uInt8* pNumLvlPos, sal_uInt8 nFollow,
1623 const wwFont* pFont, const SfxItemSet* pOutSet,
1624 sal_Int16 nIndentAt, sal_Int16 nFirstLineIndex,
1625 sal_Int16 /*nListTabPos*/, const OUString& rNumberingString,
1626 const SvxBrushItem* pBrush)
1628 m_rExport.Strm().WriteOString(SAL_NEWLINE_STRING);
1629 if (nLevel > 8) // RTF knows only 9 levels
1630 m_rExport.Strm()
1631 .WriteOString(OOO_STRING_SVTOOLS_RTF_IGNORE)
1632 .WriteOString(OOO_STRING_SVTOOLS_RTF_SOUTLVL);
1634 m_rExport.Strm().WriteChar('{').WriteOString(OOO_STRING_SVTOOLS_RTF_LISTLEVEL);
1636 sal_uInt16 nVal = 0;
1637 switch (nNumberingType)
1639 case SVX_NUM_ROMAN_UPPER:
1640 nVal = 1;
1641 break;
1642 case SVX_NUM_ROMAN_LOWER:
1643 nVal = 2;
1644 break;
1645 case SVX_NUM_CHARS_UPPER_LETTER:
1646 case SVX_NUM_CHARS_UPPER_LETTER_N:
1647 nVal = 3;
1648 break;
1649 case SVX_NUM_CHARS_LOWER_LETTER:
1650 case SVX_NUM_CHARS_LOWER_LETTER_N:
1651 nVal = 4;
1652 break;
1653 case SVX_NUM_FULL_WIDTH_ARABIC:
1654 nVal = 14;
1655 break;
1656 case SVX_NUM_CIRCLE_NUMBER:
1657 nVal = 18;
1658 break;
1659 case SVX_NUM_NUMBER_LOWER_ZH:
1660 nVal = 35;
1661 if (pOutSet)
1663 const SvxLanguageItem& rLang = pOutSet->Get(RES_CHRATR_CJK_LANGUAGE);
1664 if (rLang.GetLanguage() == LANGUAGE_CHINESE_SIMPLIFIED)
1666 nVal = 39;
1669 break;
1670 case SVX_NUM_NUMBER_UPPER_ZH:
1671 nVal = 38;
1672 break;
1673 case SVX_NUM_NUMBER_UPPER_ZH_TW:
1674 nVal = 34;
1675 break;
1676 case SVX_NUM_TIAN_GAN_ZH:
1677 nVal = 30;
1678 break;
1679 case SVX_NUM_DI_ZI_ZH:
1680 nVal = 31;
1681 break;
1682 case SVX_NUM_NUMBER_TRADITIONAL_JA:
1683 nVal = 16;
1684 break;
1685 case SVX_NUM_AIU_FULLWIDTH_JA:
1686 nVal = 20;
1687 break;
1688 case SVX_NUM_AIU_HALFWIDTH_JA:
1689 nVal = 12;
1690 break;
1691 case SVX_NUM_IROHA_FULLWIDTH_JA:
1692 nVal = 21;
1693 break;
1694 case SVX_NUM_IROHA_HALFWIDTH_JA:
1695 nVal = 13;
1696 break;
1697 case style::NumberingType::HANGUL_SYLLABLE_KO:
1698 nVal = 24;
1699 break; // ganada
1700 case style::NumberingType::HANGUL_JAMO_KO:
1701 nVal = 25;
1702 break; // chosung
1703 case style::NumberingType::HANGUL_CIRCLED_SYLLABLE_KO:
1704 nVal = 24;
1705 break;
1706 case style::NumberingType::HANGUL_CIRCLED_JAMO_KO:
1707 nVal = 25;
1708 break;
1709 case style::NumberingType::NUMBER_HANGUL_KO:
1710 nVal = 42;
1711 break; // koreanCounting
1712 case style::NumberingType::NUMBER_DIGITAL_KO:
1713 nVal = 41; // koreanDigital
1714 break;
1715 case style::NumberingType::NUMBER_DIGITAL2_KO:
1716 nVal = 44; // koreanDigital2
1717 break;
1718 case style::NumberingType::NUMBER_LEGAL_KO:
1719 nVal = 43; // koreanLegal
1720 break;
1722 case SVX_NUM_BITMAP:
1723 case SVX_NUM_CHAR_SPECIAL:
1724 nVal = 23;
1725 break;
1726 case SVX_NUM_NUMBER_NONE:
1727 nVal = 255;
1728 break;
1729 case SVX_NUM_ARABIC_ZERO:
1730 nVal = 22;
1731 break;
1733 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_LEVELNFC);
1734 m_rExport.Strm().WriteNumberAsString(nVal);
1736 switch (eAdjust)
1738 case SvxAdjust::Center:
1739 nVal = 1;
1740 break;
1741 case SvxAdjust::Right:
1742 nVal = 2;
1743 break;
1744 default:
1745 nVal = 0;
1746 break;
1748 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_LEVELJC);
1749 m_rExport.Strm().WriteNumberAsString(nVal);
1751 // bullet
1752 if (nNumberingType == SVX_NUM_BITMAP && pBrush)
1754 int nIndex = m_rExport.GetGrfIndex(*pBrush);
1755 if (nIndex != -1)
1757 m_rExport.Strm().WriteOString(LO_STRING_SVTOOLS_RTF_LEVELPICTURE);
1758 m_rExport.Strm().WriteNumberAsString(nIndex);
1762 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_LEVELSTARTAT);
1763 m_rExport.Strm().WriteNumberAsString(nStart);
1765 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_LEVELFOLLOW);
1766 m_rExport.Strm().WriteNumberAsString(nFollow);
1768 // leveltext group
1769 m_rExport.Strm().WriteChar('{').WriteOString(OOO_STRING_SVTOOLS_RTF_LEVELTEXT).WriteChar(' ');
1771 if (SVX_NUM_CHAR_SPECIAL == nNumberingType || SVX_NUM_BITMAP == nNumberingType)
1773 m_rExport.Strm().WriteOString("\\'01");
1774 sal_Unicode cChar = rNumberingString[0];
1775 m_rExport.Strm().WriteOString("\\u");
1776 m_rExport.Strm().WriteNumberAsString(cChar);
1777 m_rExport.Strm().WriteOString(" ?");
1779 else
1781 m_rExport.Strm().WriteOString("\\'").WriteOString(
1782 msfilter::rtfutil::OutHex(rNumberingString.getLength(), 2));
1783 m_rExport.Strm().WriteOString(msfilter::rtfutil::OutString(rNumberingString,
1784 m_rExport.GetDefaultEncoding(),
1785 /*bUnicode =*/false));
1788 m_rExport.Strm().WriteOString(";}");
1790 // write the levelnumbers
1791 m_rExport.Strm().WriteOString("{").WriteOString(OOO_STRING_SVTOOLS_RTF_LEVELNUMBERS);
1792 for (sal_uInt8 i = 0; i <= nLevel && pNumLvlPos[i]; ++i)
1794 m_rExport.Strm().WriteOString("\\'").WriteOString(
1795 msfilter::rtfutil::OutHex(pNumLvlPos[i], 2));
1797 m_rExport.Strm().WriteOString(";}");
1799 if (pOutSet)
1801 if (pFont)
1803 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_F);
1804 m_rExport.Strm().WriteNumberAsString(m_rExport.m_aFontHelper.GetId(*pFont));
1806 m_rExport.OutputItemSet(*pOutSet, false, true, i18n::ScriptType::LATIN,
1807 m_rExport.m_bExportModeRTF);
1808 const OString aProperties = MoveCharacterProperties(true);
1809 m_rExport.Strm().WriteOString(aProperties);
1812 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_FI);
1813 m_rExport.Strm().WriteNumberAsString(nFirstLineIndex).WriteOString(OOO_STRING_SVTOOLS_RTF_LI);
1814 m_rExport.Strm().WriteNumberAsString(nIndentAt);
1816 m_rExport.Strm().WriteChar('}');
1817 if (nLevel > 8)
1818 m_rExport.Strm().WriteChar('}');
1821 void RtfAttributeOutput::WriteField_Impl(const SwField* const pField, ww::eField /*eType*/,
1822 std::u16string_view rFieldCmd, FieldFlags nMode)
1824 // If there are no field instructions, don't export it as a field.
1825 bool bHasInstructions = !rFieldCmd.empty();
1826 if (FieldFlags::All == nMode)
1828 if (bHasInstructions)
1830 m_aRunText->append("{" OOO_STRING_SVTOOLS_RTF_FIELD);
1831 if (pField && (pField->GetSubType() & FIXEDFLD))
1832 m_aRunText->append(OOO_STRING_SVTOOLS_RTF_FLDLOCK);
1833 m_aRunText->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FLDINST
1834 " ");
1835 m_aRunText->append(
1836 msfilter::rtfutil::OutString(rFieldCmd, m_rExport.GetCurrentEncoding()));
1837 m_aRunText->append("}{" OOO_STRING_SVTOOLS_RTF_FLDRSLT " ");
1839 if (pField)
1840 m_aRunText->append(msfilter::rtfutil::OutString(pField->ExpandField(true, nullptr),
1841 m_rExport.GetDefaultEncoding()));
1842 if (bHasInstructions)
1843 m_aRunText->append("}}");
1845 else
1847 if (nMode & FieldFlags::CmdStart)
1849 m_aRunText->append("{" OOO_STRING_SVTOOLS_RTF_FIELD);
1850 m_aRunText->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FLDINST
1851 // paragraph break closes group so open another one "inside" to
1852 " {"); // prevent leaving the field instruction
1854 if (bHasInstructions)
1855 m_aRunText->append(
1856 msfilter::rtfutil::OutString(rFieldCmd, m_rExport.GetCurrentEncoding()));
1857 if (nMode & FieldFlags::CmdEnd)
1859 m_aRunText->append("}}{" OOO_STRING_SVTOOLS_RTF_FLDRSLT " {");
1861 if (nMode & FieldFlags::Close)
1863 m_aRunText->append("}}}");
1868 void RtfAttributeOutput::WriteBookmarks_Impl(std::vector<OUString>& rStarts,
1869 std::vector<OUString>& rEnds)
1871 for (const auto& rStart : rStarts)
1873 m_aRunText->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_BKMKSTART " ");
1874 m_aRunText->append(msfilter::rtfutil::OutString(rStart, m_rExport.GetCurrentEncoding()));
1875 m_aRunText->append('}');
1877 rStarts.clear();
1879 for (const auto& rEnd : rEnds)
1881 m_aRunText->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_BKMKEND " ");
1882 m_aRunText->append(msfilter::rtfutil::OutString(rEnd, m_rExport.GetCurrentEncoding()));
1883 m_aRunText->append('}');
1885 rEnds.clear();
1888 void RtfAttributeOutput::WriteAnnotationMarks_Impl(std::vector<OUString>& rStarts,
1889 std::vector<OUString>& rEnds)
1891 for (const auto& rStart : rStarts)
1893 OString rName = OUStringToOString(rStart, RTL_TEXTENCODING_UTF8);
1895 // Output the annotation mark
1896 const sal_Int32 nId = m_nNextAnnotationMarkId++;
1897 m_rOpenedAnnotationMarksIds[rName] = nId;
1898 m_aRun->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_ATRFSTART " ");
1899 m_aRun->append(nId);
1900 m_aRun->append('}');
1902 rStarts.clear();
1904 for (const auto& rEnd : rEnds)
1906 OString rName = OUStringToOString(rEnd, RTL_TEXTENCODING_UTF8);
1908 // Get the id of the annotation mark
1909 auto it = m_rOpenedAnnotationMarksIds.find(rName);
1910 if (it != m_rOpenedAnnotationMarksIds.end())
1912 const sal_Int32 nId = it->second;
1913 m_aRun->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_ATRFEND " ");
1914 m_aRun->append(nId);
1915 m_aRun->append('}');
1916 m_rOpenedAnnotationMarksIds.erase(rName);
1918 if (m_aPostitFields.find(nId) != m_aPostitFields.end())
1920 m_aRunText->append("{");
1921 m_nCurrentAnnotationMarkId = nId;
1922 PostitField(m_aPostitFields[nId]);
1923 m_nCurrentAnnotationMarkId = -1;
1924 m_aRunText->append("}");
1928 rEnds.clear();
1931 void RtfAttributeOutput::WriteHeaderFooter_Impl(const SwFrameFormat& rFormat, bool bHeader,
1932 const char* pStr, bool bTitlepg)
1934 OStringBuffer aSectionBreaks = m_aSectionBreaks;
1935 m_aSectionBreaks.setLength(0);
1936 RtfStringBuffer aRun = m_aRun;
1937 m_aRun.clear();
1939 m_aSectionHeaders.append(bHeader ? OOO_STRING_SVTOOLS_RTF_HEADERY
1940 : OOO_STRING_SVTOOLS_RTF_FOOTERY);
1941 m_aSectionHeaders.append(
1942 static_cast<sal_Int32>(m_rExport.m_pCurrentPageDesc->GetMaster().GetULSpace().GetUpper()));
1943 if (bTitlepg)
1944 m_aSectionHeaders.append(OOO_STRING_SVTOOLS_RTF_TITLEPG);
1945 m_aSectionHeaders.append('{');
1946 m_aSectionHeaders.append(pStr);
1947 m_bBufferSectionHeaders = true;
1948 m_rExport.WriteHeaderFooterText(rFormat, bHeader);
1949 m_bBufferSectionHeaders = false;
1950 m_aSectionHeaders.append('}');
1952 m_aSectionBreaks = aSectionBreaks;
1953 m_aRun = aRun;
1956 namespace
1958 void lcl_TextFrameShadow(std::vector<std::pair<OString, OString>>& rFlyProperties,
1959 const SwFrameFormat& rFrameFormat)
1961 const SvxShadowItem& aShadowItem = rFrameFormat.GetShadow();
1962 if (aShadowItem.GetLocation() == SvxShadowLocation::NONE)
1963 return;
1965 rFlyProperties.push_back(std::make_pair<OString, OString>("fShadow", OString::number(1)));
1967 const Color& rColor = aShadowItem.GetColor();
1968 // We in fact need RGB to BGR, but the transformation is symmetric.
1969 rFlyProperties.push_back(std::make_pair<OString, OString>(
1970 "shadowColor", OString::number(wwUtility::RGBToBGR(rColor))));
1972 // Twips -> points -> EMUs -- hacky, the intermediate step hides rounding errors on roundtrip.
1973 OString aShadowWidth = OString::number(sal_Int32(aShadowItem.GetWidth() / 20) * 12700);
1974 OString aOffsetX;
1975 OString aOffsetY;
1976 switch (aShadowItem.GetLocation())
1978 case SvxShadowLocation::TopLeft:
1979 aOffsetX = "-" + aShadowWidth;
1980 aOffsetY = "-" + aShadowWidth;
1981 break;
1982 case SvxShadowLocation::TopRight:
1983 aOffsetX = aShadowWidth;
1984 aOffsetY = "-" + aShadowWidth;
1985 break;
1986 case SvxShadowLocation::BottomLeft:
1987 aOffsetX = "-" + aShadowWidth;
1988 aOffsetY = aShadowWidth;
1989 break;
1990 case SvxShadowLocation::BottomRight:
1991 aOffsetX = aShadowWidth;
1992 aOffsetY = aShadowWidth;
1993 break;
1994 case SvxShadowLocation::NONE:
1995 case SvxShadowLocation::End:
1996 break;
1998 if (!aOffsetX.isEmpty())
1999 rFlyProperties.emplace_back("shadowOffsetX", aOffsetX);
2000 if (!aOffsetY.isEmpty())
2001 rFlyProperties.emplace_back("shadowOffsetY", aOffsetY);
2004 void lcl_TextFrameRelativeSize(std::vector<std::pair<OString, OString>>& rFlyProperties,
2005 const SwFrameFormat& rFrameFormat)
2007 const SwFormatFrameSize& rSize = rFrameFormat.GetFrameSize();
2009 // Relative size of the Text Frame.
2010 const sal_uInt8 nWidthPercent = rSize.GetWidthPercent();
2011 if (nWidthPercent && nWidthPercent != SwFormatFrameSize::SYNCED)
2013 rFlyProperties.push_back(
2014 std::make_pair<OString, OString>("pctHoriz", OString::number(nWidthPercent * 10)));
2016 OString aRelation;
2017 switch (rSize.GetWidthPercentRelation())
2019 case text::RelOrientation::PAGE_FRAME:
2020 aRelation = "1"; // page
2021 break;
2022 default:
2023 aRelation = "0"; // margin
2024 break;
2026 rFlyProperties.emplace_back(std::make_pair("sizerelh", aRelation));
2028 const sal_uInt8 nHeightPercent = rSize.GetHeightPercent();
2029 if (!(nHeightPercent && nHeightPercent != SwFormatFrameSize::SYNCED))
2030 return;
2032 rFlyProperties.push_back(
2033 std::make_pair<OString, OString>("pctVert", OString::number(nHeightPercent * 10)));
2035 OString aRelation;
2036 switch (rSize.GetHeightPercentRelation())
2038 case text::RelOrientation::PAGE_FRAME:
2039 aRelation = "1"; // page
2040 break;
2041 default:
2042 aRelation = "0"; // margin
2043 break;
2045 rFlyProperties.emplace_back(std::make_pair("sizerelv", aRelation));
2049 void RtfAttributeOutput::writeTextFrame(const ww8::Frame& rFrame, bool bTextBox)
2051 RtfStringBuffer aRunText;
2052 if (bTextBox)
2054 m_rExport.setStream();
2055 aRunText = m_aRunText;
2056 m_aRunText.clear();
2059 m_rExport.Strm().WriteOString("{" OOO_STRING_SVTOOLS_RTF_SHPTXT);
2062 // Save table state, in case the inner text also contains a table.
2063 ww8::WW8TableInfo::Pointer_t pTableInfoOrig = m_rExport.m_pTableInfo;
2064 m_rExport.m_pTableInfo = std::make_shared<ww8::WW8TableInfo>();
2065 std::unique_ptr<SwWriteTable> pTableWrt(std::move(m_pTableWrt));
2066 sal_uInt32 nTableDepth = m_nTableDepth;
2068 m_nTableDepth = 0;
2070 * Save m_aRun as we should not lose the opening brace.
2071 * OTOH, just drop the contents of m_aRunText in case something
2072 * would be there, causing a problem later.
2074 OString aSave = m_aRun.makeStringAndClear();
2075 // Also back m_bInRun and m_bSingleEmptyRun up.
2076 bool bInRunOrig = m_bInRun;
2077 m_bInRun = false;
2078 bool bSingleEmptyRunOrig = m_bSingleEmptyRun;
2079 m_bSingleEmptyRun = false;
2080 m_rExport.SetRTFFlySyntax(true);
2082 const SwFrameFormat& rFrameFormat = rFrame.GetFrameFormat();
2083 const SwNodeIndex* pNodeIndex = rFrameFormat.GetContent().GetContentIdx();
2084 SwNodeOffset nStt = pNodeIndex ? pNodeIndex->GetIndex() + 1 : SwNodeOffset(0);
2085 SwNodeOffset nEnd
2086 = pNodeIndex ? pNodeIndex->GetNode().EndOfSectionIndex() : SwNodeOffset(0);
2087 m_rExport.SaveData(nStt, nEnd);
2088 m_rExport.m_pParentFrame = &rFrame;
2089 m_rExport.WriteText();
2090 m_rExport.RestoreData();
2092 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_PARD);
2093 m_rExport.SetRTFFlySyntax(false);
2094 m_aRun->append(aSave);
2095 m_aRunText.clear();
2096 m_bInRun = bInRunOrig;
2097 m_bSingleEmptyRun = bSingleEmptyRunOrig;
2099 // Restore table state.
2100 m_rExport.m_pTableInfo = pTableInfoOrig;
2101 m_pTableWrt = std::move(pTableWrt);
2102 m_nTableDepth = nTableDepth;
2105 m_rExport.m_pParentFrame = nullptr;
2107 m_rExport.Strm().WriteChar('}'); // shptxt
2109 if (bTextBox)
2111 m_aRunText = aRunText;
2112 m_aRunText->append(m_rExport.getStream());
2113 m_rExport.resetStream();
2117 /** save the current run state around exporting things that contain paragraphs
2118 themselves like text frames.
2119 TODO: probably more things need to be saved?
2121 class SaveRunState
2123 private:
2124 RtfAttributeOutput& m_rRtf;
2125 RtfStringBuffer m_Run;
2126 RtfStringBuffer m_RunText;
2127 bool const m_bSingleEmptyRun;
2128 bool const m_bInRun;
2130 public:
2131 explicit SaveRunState(RtfAttributeOutput& rRtf)
2132 : m_rRtf(rRtf)
2133 , m_Run(std::move(rRtf.m_aRun))
2134 , m_RunText(std::move(rRtf.m_aRunText))
2135 , m_bSingleEmptyRun(rRtf.m_bSingleEmptyRun)
2136 , m_bInRun(rRtf.m_bInRun)
2138 m_rRtf.m_rExport.setStream();
2140 ~SaveRunState()
2142 m_rRtf.m_aRun = std::move(m_Run);
2143 m_rRtf.m_aRunText = std::move(m_RunText);
2144 m_rRtf.m_bSingleEmptyRun = m_bSingleEmptyRun;
2145 m_rRtf.m_bInRun = m_bInRun;
2147 m_rRtf.m_aRunText->append(m_rRtf.m_rExport.getStream());
2148 m_rRtf.m_rExport.resetStream();
2152 void RtfAttributeOutput::OutputFlyFrame_Impl(const ww8::Frame& rFrame, const Point& /*rNdTopLeft*/)
2154 const SwFrameFormat& rFrameFormat = rFrame.GetFrameFormat();
2155 if (rFrameFormat.GetFlySplit().GetValue())
2157 // The frame can split: this was originally from a floating table, write it back as
2158 // such.
2159 SaveRunState aState(*this);
2160 const SwNodeIndex* pNodeIndex = rFrameFormat.GetContent().GetContentIdx();
2161 SwNodeOffset nStt = pNodeIndex ? pNodeIndex->GetIndex() + 1 : SwNodeOffset(0);
2162 SwNodeOffset nEnd
2163 = pNodeIndex ? pNodeIndex->GetNode().EndOfSectionIndex() : SwNodeOffset(0);
2164 m_rExport.SaveData(nStt, nEnd);
2165 GetExport().WriteText();
2166 m_rExport.RestoreData();
2167 return;
2170 const SwNode* pNode = rFrame.GetContent();
2171 const SwGrfNode* pGrfNode = pNode ? pNode->GetGrfNode() : nullptr;
2173 switch (rFrame.GetWriterType())
2175 case ww8::Frame::eTextBox:
2177 // If this is a TextBox of a shape, then ignore: it's handled in RtfSdrExport::StartShape().
2178 if (RtfSdrExport::isTextBox(rFrame.GetFrameFormat()))
2179 break;
2181 SaveRunState const saved(*this);
2183 m_rExport.m_pParentFrame = &rFrame;
2185 m_rExport.Strm().WriteOString("{" OOO_STRING_SVTOOLS_RTF_SHP);
2186 m_rExport.Strm().WriteOString(
2187 "{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_SHPINST);
2189 // Shape properties.
2190 m_aFlyProperties.push_back(std::make_pair<OString, OString>(
2191 "shapeType", OString::number(ESCHER_ShpInst_TextBox)));
2193 // When a frame has some low height, but automatically expanded due
2194 // to lots of contents, this size contains the real size.
2195 const Size aSize = rFrame.GetSize();
2196 m_pFlyFrameSize = &aSize;
2198 m_rExport.m_bOutFlyFrameAttrs = true;
2199 m_rExport.SetRTFFlySyntax(true);
2200 m_rExport.OutputFormat(rFrame.GetFrameFormat(), false, false, true);
2202 // Write ZOrder.
2203 if (const SdrObject* pObject = rFrame.GetFrameFormat().FindRealSdrObject())
2205 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_SHPZ);
2206 m_rExport.Strm().WriteNumberAsString(pObject->GetOrdNum());
2209 m_rExport.Strm().WriteOString(m_aRunText.makeStringAndClear());
2210 m_rExport.Strm().WriteOString(m_aStyles);
2211 m_aStyles.setLength(0);
2212 m_rExport.m_bOutFlyFrameAttrs = false;
2213 m_rExport.SetRTFFlySyntax(false);
2214 m_pFlyFrameSize = nullptr;
2216 lcl_TextFrameShadow(m_aFlyProperties, rFrameFormat);
2217 lcl_TextFrameRelativeSize(m_aFlyProperties, rFrameFormat);
2219 for (const std::pair<OString, OString>& rPair : m_aFlyProperties)
2221 m_rExport.Strm().WriteOString("{" OOO_STRING_SVTOOLS_RTF_SP "{");
2222 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_SN " ");
2223 m_rExport.Strm().WriteOString(rPair.first);
2224 m_rExport.Strm().WriteOString("}{" OOO_STRING_SVTOOLS_RTF_SV " ");
2225 m_rExport.Strm().WriteOString(rPair.second);
2226 m_rExport.Strm().WriteOString("}}");
2228 m_aFlyProperties.clear();
2230 writeTextFrame(rFrame);
2232 m_rExport.Strm().WriteChar('}'); // shpinst
2233 m_rExport.Strm().WriteChar('}'); // shp
2235 m_rExport.Strm().WriteOString(SAL_NEWLINE_STRING);
2237 break;
2238 case ww8::Frame::eGraphic:
2239 if (pGrfNode)
2241 m_aRunText.append(dynamic_cast<const SwFlyFrameFormat*>(&rFrame.GetFrameFormat()),
2242 pGrfNode);
2244 else if (!rFrame.IsInline())
2246 m_rExport.m_pParentFrame = &rFrame;
2247 m_rExport.SetRTFFlySyntax(true);
2248 m_rExport.OutputFormat(rFrame.GetFrameFormat(), false, false, true);
2249 m_rExport.SetRTFFlySyntax(false);
2250 m_aRunText->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE);
2251 m_rExport.OutputFormat(rFrame.GetFrameFormat(), false, false, true);
2252 m_aRunText->append('}');
2253 m_rExport.m_pParentFrame = nullptr;
2255 break;
2256 case ww8::Frame::eDrawing:
2258 const SdrObject* pSdrObj = rFrame.GetFrameFormat().FindRealSdrObject();
2259 if (pSdrObj)
2261 m_aRunText->append("{" OOO_STRING_SVTOOLS_RTF_FIELD "{");
2262 m_aRunText->append(OOO_STRING_SVTOOLS_RTF_IGNORE);
2263 m_aRunText->append(OOO_STRING_SVTOOLS_RTF_FLDINST);
2264 m_aRunText->append(" SHAPE ");
2265 m_aRunText->append("}"
2266 "{" OOO_STRING_SVTOOLS_RTF_FLDRSLT);
2268 m_rExport.SdrExporter().AddSdrObject(*pSdrObj);
2270 m_aRunText->append('}');
2271 m_aRunText->append('}');
2274 break;
2275 case ww8::Frame::eFormControl:
2277 const SdrObject* pObject = rFrameFormat.FindRealSdrObject();
2279 m_aRun->append("{" OOO_STRING_SVTOOLS_RTF_FIELD);
2280 m_aRun->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FLDINST);
2282 if (pObject && pObject->GetObjInventor() == SdrInventor::FmForm)
2284 if (auto pFormObj = dynamic_cast<const SdrUnoObj*>(pObject))
2286 const uno::Reference<awt::XControlModel>& xControlModel
2287 = pFormObj->GetUnoControlModel();
2288 uno::Reference<lang::XServiceInfo> xInfo(xControlModel, uno::UNO_QUERY);
2289 if (xInfo.is())
2291 uno::Reference<beans::XPropertySet> xPropSet(xControlModel, uno::UNO_QUERY);
2292 uno::Reference<beans::XPropertySetInfo> xPropSetInfo
2293 = xPropSet->getPropertySetInfo();
2294 OUString sName;
2295 if (xInfo->supportsService("com.sun.star.form.component.CheckBox"))
2297 m_aRun->append(OUStringToOString(FieldString(ww::eFORMCHECKBOX),
2298 m_rExport.GetCurrentEncoding()));
2299 m_aRun->append(
2300 "{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FORMFIELD
2301 "{");
2302 m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFTYPE "1"); // 1 = checkbox
2303 // checkbox size in half points, this seems to be always 20
2304 m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFHPS "20");
2306 OUString aStr;
2307 sName = "Name";
2308 if (xPropSetInfo->hasPropertyByName(sName))
2310 xPropSet->getPropertyValue(sName) >>= aStr;
2311 m_aRun->append(
2312 "{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FFNAME
2313 " ");
2314 m_aRun->append(
2315 OUStringToOString(aStr, m_rExport.GetCurrentEncoding()));
2316 m_aRun->append('}');
2319 sName = "HelpText";
2320 if (xPropSetInfo->hasPropertyByName(sName))
2322 xPropSet->getPropertyValue(sName) >>= aStr;
2323 m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFOWNHELP);
2324 m_aRun->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE
2325 OOO_STRING_SVTOOLS_RTF_FFHELPTEXT " ");
2326 m_aRun->append(
2327 OUStringToOString(aStr, m_rExport.GetCurrentEncoding()));
2328 m_aRun->append('}');
2331 sName = "HelpF1Text";
2332 if (xPropSetInfo->hasPropertyByName(sName))
2334 xPropSet->getPropertyValue(sName) >>= aStr;
2335 m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFOWNSTAT);
2336 m_aRun->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE
2337 OOO_STRING_SVTOOLS_RTF_FFSTATTEXT " ");
2338 m_aRun->append(
2339 OUStringToOString(aStr, m_rExport.GetCurrentEncoding()));
2340 m_aRun->append('}');
2343 sal_Int16 nTemp = 0;
2344 xPropSet->getPropertyValue("DefaultState") >>= nTemp;
2345 m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFDEFRES);
2346 m_aRun->append(static_cast<sal_Int32>(nTemp));
2347 xPropSet->getPropertyValue("State") >>= nTemp;
2348 m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFRES);
2349 m_aRun->append(static_cast<sal_Int32>(nTemp));
2351 m_aRun->append("}}");
2353 // field result is empty, ffres already contains the form result
2354 m_aRun->append("}{" OOO_STRING_SVTOOLS_RTF_FLDRSLT " ");
2356 else if (xInfo->supportsService("com.sun.star.form.component.TextField"))
2358 OStringBuffer aBuf;
2359 OString aStr;
2360 OUString aTmp;
2361 const char* pStr;
2363 m_aRun->append(OUStringToOString(FieldString(ww::eFORMTEXT),
2364 m_rExport.GetCurrentEncoding()));
2365 m_aRun->append(
2366 "{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_DATAFIELD
2367 " ");
2368 for (int i = 0; i < 8; i++)
2369 aBuf.append(char(0x00));
2370 xPropSet->getPropertyValue("Name") >>= aTmp;
2371 aStr = OUStringToOString(aTmp, m_rExport.GetCurrentEncoding());
2372 aBuf.append(OStringChar(static_cast<char>(aStr.getLength())) + aStr
2373 + OStringChar(char(0x00)));
2374 xPropSet->getPropertyValue("DefaultText") >>= aTmp;
2375 aStr = OUStringToOString(aTmp, m_rExport.GetCurrentEncoding());
2376 aBuf.append(static_cast<char>(aStr.getLength()));
2377 aBuf.append(aStr);
2378 for (int i = 0; i < 11; i++)
2379 aBuf.append(char(0x00));
2380 aStr = aBuf.makeStringAndClear();
2381 pStr = aStr.getStr();
2382 for (int i = 0; i < aStr.getLength(); i++, pStr++)
2383 m_aRun->append(msfilter::rtfutil::OutHex(*pStr, 2));
2384 m_aRun->append('}');
2385 m_aRun->append("}{" OOO_STRING_SVTOOLS_RTF_FLDRSLT " ");
2386 xPropSet->getPropertyValue("Text") >>= aTmp;
2387 m_aRun->append(OUStringToOString(aTmp, m_rExport.GetCurrentEncoding()));
2388 m_aRun->append('}');
2389 m_aRun->append(
2390 "{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FORMFIELD
2391 "{");
2392 sName = "HelpText";
2393 if (xPropSetInfo->hasPropertyByName(sName))
2395 xPropSet->getPropertyValue(sName) >>= aTmp;
2396 m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFOWNHELP);
2397 m_aRun->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE
2398 OOO_STRING_SVTOOLS_RTF_FFHELPTEXT " ");
2399 m_aRun->append(
2400 OUStringToOString(aTmp, m_rExport.GetCurrentEncoding()));
2401 m_aRun->append('}');
2404 sName = "HelpF1Text";
2405 if (xPropSetInfo->hasPropertyByName(sName))
2407 xPropSet->getPropertyValue(sName) >>= aTmp;
2408 m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFOWNSTAT);
2409 m_aRun->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE
2410 OOO_STRING_SVTOOLS_RTF_FFSTATTEXT " ");
2411 m_aRun->append(
2412 OUStringToOString(aTmp, m_rExport.GetCurrentEncoding()));
2413 m_aRun->append('}');
2415 m_aRun->append("}");
2417 else if (xInfo->supportsService("com.sun.star.form.component.ListBox"))
2419 OUString aStr;
2420 uno::Sequence<sal_Int16> aIntSeq;
2421 uno::Sequence<OUString> aStrSeq;
2423 m_aRun->append(OUStringToOString(FieldString(ww::eFORMDROPDOWN),
2424 m_rExport.GetCurrentEncoding()));
2425 m_aRun->append(
2426 "{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FORMFIELD
2427 "{");
2428 m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFTYPE "2"); // 2 = list
2429 m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFHASLISTBOX);
2431 xPropSet->getPropertyValue("DefaultSelection") >>= aIntSeq;
2432 if (aIntSeq.hasElements())
2434 m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFDEFRES);
2435 // a dropdown list can have only one 'selected item by default'
2436 m_aRun->append(static_cast<sal_Int32>(aIntSeq[0]));
2439 xPropSet->getPropertyValue("SelectedItems") >>= aIntSeq;
2440 if (aIntSeq.hasElements())
2442 m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFRES);
2443 // a dropdown list can have only one 'currently selected item'
2444 m_aRun->append(static_cast<sal_Int32>(aIntSeq[0]));
2447 sName = "Name";
2448 if (xPropSetInfo->hasPropertyByName(sName))
2450 xPropSet->getPropertyValue(sName) >>= aStr;
2451 m_aRun->append(
2452 "{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FFNAME
2453 " ");
2454 m_aRun->append(
2455 OUStringToOString(aStr, m_rExport.GetCurrentEncoding()));
2456 m_aRun->append('}');
2459 sName = "HelpText";
2460 if (xPropSetInfo->hasPropertyByName(sName))
2462 xPropSet->getPropertyValue(sName) >>= aStr;
2463 m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFOWNHELP);
2464 m_aRun->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE
2465 OOO_STRING_SVTOOLS_RTF_FFHELPTEXT " ");
2466 m_aRun->append(
2467 OUStringToOString(aStr, m_rExport.GetCurrentEncoding()));
2468 m_aRun->append('}');
2471 sName = "HelpF1Text";
2472 if (xPropSetInfo->hasPropertyByName(sName))
2474 xPropSet->getPropertyValue(sName) >>= aStr;
2475 m_aRun->append(OOO_STRING_SVTOOLS_RTF_FFOWNSTAT);
2476 m_aRun->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE
2477 OOO_STRING_SVTOOLS_RTF_FFSTATTEXT " ");
2478 m_aRun->append(
2479 OUStringToOString(aStr, m_rExport.GetCurrentEncoding()));
2480 m_aRun->append('}');
2483 xPropSet->getPropertyValue("StringItemList") >>= aStrSeq;
2484 for (const auto& rStr : std::as_const(aStrSeq))
2485 m_aRun->append(
2486 "{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FFL " "
2487 + OUStringToOString(rStr, m_rExport.GetCurrentEncoding())
2488 + "}");
2490 m_aRun->append("}}");
2492 // field result is empty, ffres already contains the form result
2493 m_aRun->append("}{" OOO_STRING_SVTOOLS_RTF_FLDRSLT " ");
2495 else
2496 SAL_INFO("sw.rtf", __func__ << " unhandled form control: '"
2497 << xInfo->getImplementationName() << "'");
2498 m_aRun->append('}');
2503 m_aRun->append('}');
2505 break;
2506 case ww8::Frame::eOle:
2508 const SdrObject* pSdrObj = rFrameFormat.FindRealSdrObject();
2509 if (pSdrObj)
2511 SwNodeIndex aIdx(*rFrameFormat.GetContent().GetContentIdx(), 1);
2512 SwOLENode& rOLENd = *aIdx.GetNode().GetOLENode();
2513 FlyFrameOLE(dynamic_cast<const SwFlyFrameFormat*>(&rFrameFormat), rOLENd,
2514 rFrame.GetLayoutSize());
2517 break;
2518 default:
2519 SAL_INFO("sw.rtf", __func__ << ": unknown type ("
2520 << static_cast<int>(rFrame.GetWriterType()) << ")");
2521 break;
2525 void RtfAttributeOutput::CharCaseMap(const SvxCaseMapItem& rCaseMap)
2527 switch (rCaseMap.GetValue())
2529 case SvxCaseMap::SmallCaps:
2530 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SCAPS);
2531 break;
2532 case SvxCaseMap::Uppercase:
2533 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_CAPS);
2534 break;
2535 default: // Something that rtf does not support
2536 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SCAPS);
2537 m_aStyles.append(sal_Int32(0));
2538 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_CAPS);
2539 m_aStyles.append(sal_Int32(0));
2540 break;
2544 void RtfAttributeOutput::CharColor(const SvxColorItem& rColor)
2546 const Color aColor(rColor.GetValue());
2548 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_CF);
2549 m_aStyles.append(static_cast<sal_Int32>(m_rExport.GetColor(aColor)));
2552 void RtfAttributeOutput::CharContour(const SvxContourItem& rContour)
2554 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_OUTL);
2555 if (!rContour.GetValue())
2556 m_aStyles.append(sal_Int32(0));
2559 void RtfAttributeOutput::CharCrossedOut(const SvxCrossedOutItem& rCrossedOut)
2561 switch (rCrossedOut.GetStrikeout())
2563 case STRIKEOUT_NONE:
2564 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_STRIKE);
2565 m_aStyles.append(sal_Int32(0));
2566 break;
2567 case STRIKEOUT_DOUBLE:
2568 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_STRIKED);
2569 m_aStyles.append(sal_Int32(1));
2570 break;
2571 default:
2572 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_STRIKE);
2573 break;
2577 void RtfAttributeOutput::CharEscapement(const SvxEscapementItem& rEscapement)
2579 short nEsc = rEscapement.GetEsc();
2580 short nProp = rEscapement.GetProportionalHeight();
2581 sal_Int32 nProp100 = nProp * 100;
2582 if (DFLT_ESC_PROP == nProp || nProp < 1 || nProp > 100)
2584 if (DFLT_ESC_SUB == nEsc || DFLT_ESC_AUTO_SUB == nEsc)
2585 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SUB);
2586 else if (DFLT_ESC_SUPER == nEsc || DFLT_ESC_AUTO_SUPER == nEsc)
2587 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SUPER);
2588 return;
2590 if (DFLT_ESC_AUTO_SUPER == nEsc)
2592 nEsc = .8 * (100 - nProp);
2593 ++nProp100; // A 1 afterwards means 'automatic' according to editeng/rtf/rtfitem.cxx
2595 else if (DFLT_ESC_AUTO_SUB == nEsc)
2597 nEsc = .2 * -(100 - nProp);
2598 ++nProp100;
2601 const char* pUpDn;
2603 double fHeight = m_rExport.GetItem(RES_CHRATR_FONTSIZE).GetHeight();
2605 if (0 < nEsc)
2606 pUpDn = OOO_STRING_SVTOOLS_RTF_UP;
2607 else if (0 > nEsc)
2609 pUpDn = OOO_STRING_SVTOOLS_RTF_DN;
2610 fHeight = -fHeight;
2612 else
2613 return;
2615 m_aStyles.append('{');
2616 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_IGNORE);
2617 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_UPDNPROP);
2618 m_aStyles.append(nProp100);
2619 m_aStyles.append('}');
2620 m_aStyles.append(pUpDn);
2623 * Calculate the act. FontSize and the percentage of the displacement;
2624 * RTF file expects half points, while internally it's in twips.
2625 * Formally : (FontSize * 1/20 ) pts x * 2
2626 * ----------------------- = ------------
2627 * 100% Escapement
2629 m_aStyles.append(static_cast<sal_Int32>(round(fHeight * nEsc / 1000)));
2632 void RtfAttributeOutput::CharFont(const SvxFontItem& rFont)
2634 // Insert \loch in MoveCharacterProperties
2635 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_F);
2636 m_aStyles.append(static_cast<sal_Int32>(m_rExport.m_aFontHelper.GetId(rFont)));
2638 // Insert \hich in MoveCharacterProperties
2639 m_aStylesAssocHich.append(OOO_STRING_SVTOOLS_RTF_AF);
2640 m_aStylesAssocHich.append(static_cast<sal_Int32>(m_rExport.m_aFontHelper.GetId(rFont)));
2642 // FIXME: this may be a tad expensive... but the charset needs to be
2643 // consistent with what wwFont::WriteRtf() does
2644 sw::util::FontMapExport aTmp(rFont.GetFamilyName());
2645 sal_uInt8 nWindowsCharset = sw::ms::rtl_TextEncodingToWinCharsetRTF(
2646 aTmp.msPrimary, aTmp.msSecondary, rFont.GetCharSet());
2647 m_rExport.SetCurrentEncoding(rtl_getTextEncodingFromWindowsCharset(nWindowsCharset));
2648 if (m_rExport.GetCurrentEncoding() == RTL_TEXTENCODING_DONTKNOW)
2649 m_rExport.SetCurrentEncoding(m_rExport.GetDefaultEncoding());
2652 void RtfAttributeOutput::CharFontSize(const SvxFontHeightItem& rFontSize)
2654 switch (rFontSize.Which())
2656 case RES_CHRATR_FONTSIZE:
2657 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_FS);
2658 m_aStyles.append(static_cast<sal_Int32>(rFontSize.GetHeight() / 10));
2659 break;
2660 case RES_CHRATR_CJK_FONTSIZE:
2661 m_aStylesAssocDbch.append(OOO_STRING_SVTOOLS_RTF_AFS);
2662 m_aStylesAssocDbch.append(static_cast<sal_Int32>(rFontSize.GetHeight() / 10));
2663 break;
2664 case RES_CHRATR_CTL_FONTSIZE:
2665 m_aStylesAssocRtlch.append(OOO_STRING_SVTOOLS_RTF_AFS);
2666 m_aStylesAssocRtlch.append(static_cast<sal_Int32>(rFontSize.GetHeight() / 10));
2667 break;
2671 void RtfAttributeOutput::CharKerning(const SvxKerningItem& rKerning)
2673 // in quarter points then in twips
2674 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_EXPND);
2675 m_aStyles.append(static_cast<sal_Int32>(rKerning.GetValue() / 5));
2676 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_EXPNDTW);
2677 m_aStyles.append(static_cast<sal_Int32>(rKerning.GetValue()));
2680 void RtfAttributeOutput::CharLanguage(const SvxLanguageItem& rLanguage)
2682 switch (rLanguage.Which())
2684 case RES_CHRATR_LANGUAGE:
2685 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_LANG);
2686 m_aStyles.append(
2687 static_cast<sal_Int32>(static_cast<sal_uInt16>(rLanguage.GetLanguage())));
2688 m_aStylesAssocLtrch.append(OOO_STRING_SVTOOLS_RTF_LANG);
2689 m_aStylesAssocLtrch.append(
2690 static_cast<sal_Int32>(static_cast<sal_uInt16>(rLanguage.GetLanguage())));
2691 break;
2692 case RES_CHRATR_CJK_LANGUAGE:
2693 m_aStylesAssocDbch.append(OOO_STRING_SVTOOLS_RTF_LANGFE);
2694 m_aStylesAssocDbch.append(
2695 static_cast<sal_Int32>(static_cast<sal_uInt16>(rLanguage.GetLanguage())));
2696 m_aStylesAssocLtrch.append(OOO_STRING_SVTOOLS_RTF_LANGFE);
2697 m_aStylesAssocLtrch.append(
2698 static_cast<sal_Int32>(static_cast<sal_uInt16>(rLanguage.GetLanguage())));
2699 break;
2700 case RES_CHRATR_CTL_LANGUAGE:
2701 m_aStylesAssocRtlch.append(OOO_STRING_SVTOOLS_RTF_ALANG);
2702 m_aStylesAssocRtlch.append(
2703 static_cast<sal_Int32>(static_cast<sal_uInt16>(rLanguage.GetLanguage())));
2704 break;
2708 void RtfAttributeOutput::CharPosture(const SvxPostureItem& rPosture)
2710 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_I);
2711 if (rPosture.GetPosture() == ITALIC_NONE)
2712 m_aStyles.append(sal_Int32(0));
2715 void RtfAttributeOutput::CharShadow(const SvxShadowedItem& rShadow)
2717 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SHAD);
2718 if (!rShadow.GetValue())
2719 m_aStyles.append(sal_Int32(0));
2722 void RtfAttributeOutput::CharUnderline(const SvxUnderlineItem& rUnderline)
2724 const char* pStr = nullptr;
2725 const SfxPoolItem* pItem = m_rExport.HasItem(RES_CHRATR_WORDLINEMODE);
2726 bool bWord = false;
2727 // No StaticWhichCast(RES_CHRATR_WORDLINEMODE), this may be for a postit, where the which ids
2728 // don't match.
2729 if (pItem)
2730 bWord = static_cast<const SvxWordLineModeItem*>(pItem)->GetValue();
2731 switch (rUnderline.GetLineStyle())
2733 case LINESTYLE_SINGLE:
2734 pStr = bWord ? OOO_STRING_SVTOOLS_RTF_ULW : OOO_STRING_SVTOOLS_RTF_UL;
2735 break;
2736 case LINESTYLE_DOUBLE:
2737 pStr = OOO_STRING_SVTOOLS_RTF_ULDB;
2738 break;
2739 case LINESTYLE_NONE:
2740 pStr = OOO_STRING_SVTOOLS_RTF_ULNONE;
2741 break;
2742 case LINESTYLE_DOTTED:
2743 pStr = OOO_STRING_SVTOOLS_RTF_ULD;
2744 break;
2745 case LINESTYLE_DASH:
2746 pStr = OOO_STRING_SVTOOLS_RTF_ULDASH;
2747 break;
2748 case LINESTYLE_DASHDOT:
2749 pStr = OOO_STRING_SVTOOLS_RTF_ULDASHD;
2750 break;
2751 case LINESTYLE_DASHDOTDOT:
2752 pStr = OOO_STRING_SVTOOLS_RTF_ULDASHDD;
2753 break;
2754 case LINESTYLE_BOLD:
2755 pStr = OOO_STRING_SVTOOLS_RTF_ULTH;
2756 break;
2757 case LINESTYLE_WAVE:
2758 pStr = OOO_STRING_SVTOOLS_RTF_ULWAVE;
2759 break;
2760 case LINESTYLE_BOLDDOTTED:
2761 pStr = OOO_STRING_SVTOOLS_RTF_ULTHD;
2762 break;
2763 case LINESTYLE_BOLDDASH:
2764 pStr = OOO_STRING_SVTOOLS_RTF_ULTHDASH;
2765 break;
2766 case LINESTYLE_LONGDASH:
2767 pStr = OOO_STRING_SVTOOLS_RTF_ULLDASH;
2768 break;
2769 case LINESTYLE_BOLDLONGDASH:
2770 pStr = OOO_STRING_SVTOOLS_RTF_ULTHLDASH;
2771 break;
2772 case LINESTYLE_BOLDDASHDOT:
2773 pStr = OOO_STRING_SVTOOLS_RTF_ULTHDASHD;
2774 break;
2775 case LINESTYLE_BOLDDASHDOTDOT:
2776 pStr = OOO_STRING_SVTOOLS_RTF_ULTHDASHDD;
2777 break;
2778 case LINESTYLE_BOLDWAVE:
2779 pStr = OOO_STRING_SVTOOLS_RTF_ULHWAVE;
2780 break;
2781 case LINESTYLE_DOUBLEWAVE:
2782 pStr = OOO_STRING_SVTOOLS_RTF_ULULDBWAVE;
2783 break;
2784 default:
2785 break;
2788 if (pStr)
2790 m_aStyles.append(pStr);
2791 // NEEDSWORK looks like here rUnderline.GetColor() is always black,
2792 // even if the color in the odt is for example green...
2793 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ULC);
2794 m_aStyles.append(static_cast<sal_Int32>(m_rExport.GetColor(rUnderline.GetColor())));
2798 void RtfAttributeOutput::CharWeight(const SvxWeightItem& rWeight)
2800 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_B);
2801 if (rWeight.GetWeight() != WEIGHT_BOLD)
2802 m_aStyles.append(sal_Int32(0));
2805 void RtfAttributeOutput::CharAutoKern(const SvxAutoKernItem& rAutoKern)
2807 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_KERNING);
2808 m_aStyles.append(static_cast<sal_Int32>(rAutoKern.GetValue() ? 1 : 0));
2811 void RtfAttributeOutput::CharAnimatedText(const SvxBlinkItem& rBlink)
2813 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ANIMTEXT);
2814 m_aStyles.append(static_cast<sal_Int32>(rBlink.GetValue() ? 2 : 0));
2817 void RtfAttributeOutput::CharBackground(const SvxBrushItem& rBrush)
2819 if (!rBrush.GetColor().IsTransparent())
2821 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_CHCBPAT);
2822 m_aStyles.append(static_cast<sal_Int32>(m_rExport.GetColor(rBrush.GetColor())));
2826 void RtfAttributeOutput::CharFontCJK(const SvxFontItem& rFont)
2828 // Insert \dbch in MoveCharacterProperties
2829 m_aStylesAssocDbch.append(OOO_STRING_SVTOOLS_RTF_AF);
2830 m_aStylesAssocDbch.append(static_cast<sal_Int32>(m_rExport.m_aFontHelper.GetId(rFont)));
2833 void RtfAttributeOutput::CharFontSizeCJK(const SvxFontHeightItem& rFontSize)
2835 CharFontSize(rFontSize);
2838 void RtfAttributeOutput::CharLanguageCJK(const SvxLanguageItem& rLanguageItem)
2840 CharLanguage(rLanguageItem);
2843 void RtfAttributeOutput::CharPostureCJK(const SvxPostureItem& rPosture)
2845 m_aStylesAssocDbch.append(OOO_STRING_SVTOOLS_RTF_I);
2846 if (rPosture.GetPosture() == ITALIC_NONE)
2847 m_aStylesAssocDbch.append(sal_Int32(0));
2850 void RtfAttributeOutput::CharWeightCJK(const SvxWeightItem& rWeight)
2852 m_aStylesAssocDbch.append(OOO_STRING_SVTOOLS_RTF_AB);
2853 if (rWeight.GetWeight() != WEIGHT_BOLD)
2854 m_aStylesAssocDbch.append(sal_Int32(0));
2857 void RtfAttributeOutput::CharFontCTL(const SvxFontItem& rFont)
2859 // Insert \rtlch in MoveCharacterProperties
2860 m_aStylesAssocRtlch.append(OOO_STRING_SVTOOLS_RTF_AF);
2861 m_aStylesAssocRtlch.append(static_cast<sal_Int32>(m_rExport.m_aFontHelper.GetId(rFont)));
2864 void RtfAttributeOutput::CharFontSizeCTL(const SvxFontHeightItem& rFontSize)
2866 CharFontSize(rFontSize);
2869 void RtfAttributeOutput::CharLanguageCTL(const SvxLanguageItem& rLanguageItem)
2871 CharLanguage(rLanguageItem);
2874 void RtfAttributeOutput::CharPostureCTL(const SvxPostureItem& rPosture)
2876 m_aStylesAssocRtlch.append(OOO_STRING_SVTOOLS_RTF_AI);
2877 if (rPosture.GetPosture() == ITALIC_NONE)
2878 m_aStylesAssocRtlch.append(sal_Int32(0));
2881 void RtfAttributeOutput::CharWeightCTL(const SvxWeightItem& rWeight)
2883 m_aStylesAssocRtlch.append(OOO_STRING_SVTOOLS_RTF_AB);
2884 if (rWeight.GetWeight() != WEIGHT_BOLD)
2885 m_aStylesAssocRtlch.append(sal_Int32(0));
2888 void RtfAttributeOutput::CharBidiRTL(const SfxPoolItem& /*rItem*/) {}
2890 void RtfAttributeOutput::CharIdctHint(const SfxPoolItem& /*rItem*/) {}
2892 void RtfAttributeOutput::CharRotate(const SvxCharRotateItem& rRotate)
2894 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_HORZVERT);
2895 m_aStyles.append(static_cast<sal_Int32>(rRotate.IsFitToLine() ? 1 : 0));
2898 void RtfAttributeOutput::CharEmphasisMark(const SvxEmphasisMarkItem& rEmphasisMark)
2900 FontEmphasisMark v = rEmphasisMark.GetEmphasisMark();
2901 if (v == FontEmphasisMark::NONE)
2902 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ACCNONE);
2903 else if (v == (FontEmphasisMark::Dot | FontEmphasisMark::PosAbove))
2904 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ACCDOT);
2905 else if (v == (FontEmphasisMark::Accent | FontEmphasisMark::PosAbove))
2906 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ACCCOMMA);
2907 else if (v == (FontEmphasisMark::Circle | FontEmphasisMark::PosAbove))
2908 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ACCCIRCLE);
2909 else if (v == (FontEmphasisMark::Dot | FontEmphasisMark::PosBelow))
2910 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ACCUNDERDOT);
2913 void RtfAttributeOutput::CharTwoLines(const SvxTwoLinesItem& rTwoLines)
2915 if (!rTwoLines.GetValue())
2916 return;
2918 sal_Unicode cStart = rTwoLines.GetStartBracket();
2919 sal_Unicode cEnd = rTwoLines.GetEndBracket();
2921 sal_uInt16 nType;
2922 if (!cStart && !cEnd)
2923 nType = 0;
2924 else if ('{' == cStart || '}' == cEnd)
2925 nType = 4;
2926 else if ('<' == cStart || '>' == cEnd)
2927 nType = 3;
2928 else if ('[' == cStart || ']' == cEnd)
2929 nType = 2;
2930 else // all other kind of brackets
2931 nType = 1;
2933 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_TWOINONE);
2934 m_aStyles.append(static_cast<sal_Int32>(nType));
2937 void RtfAttributeOutput::CharScaleWidth(const SvxCharScaleWidthItem& rScaleWidth)
2939 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_CHARSCALEX);
2940 m_aStyles.append(static_cast<sal_Int32>(rScaleWidth.GetValue()));
2943 void RtfAttributeOutput::CharRelief(const SvxCharReliefItem& rRelief)
2945 const char* pStr;
2946 switch (rRelief.GetValue())
2948 case FontRelief::Embossed:
2949 pStr = OOO_STRING_SVTOOLS_RTF_EMBO;
2950 break;
2951 case FontRelief::Engraved:
2952 pStr = OOO_STRING_SVTOOLS_RTF_IMPR;
2953 break;
2954 default:
2955 pStr = nullptr;
2956 break;
2959 if (pStr)
2960 m_aStyles.append(pStr);
2963 void RtfAttributeOutput::CharHidden(const SvxCharHiddenItem& rHidden)
2965 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_V);
2966 if (!rHidden.GetValue())
2967 m_aStyles.append(sal_Int32(0));
2970 void RtfAttributeOutput::CharBorder(const editeng::SvxBorderLine* pAllBorder,
2971 const sal_uInt16 nDist, const bool bShadow)
2973 m_aStyles.append(
2974 OutBorderLine(m_rExport, pAllBorder, OOO_STRING_SVTOOLS_RTF_CHBRDR, nDist,
2975 bShadow ? SvxShadowLocation::BottomRight : SvxShadowLocation::NONE));
2978 void RtfAttributeOutput::CharHighlight(const SvxBrushItem& rBrush)
2980 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_HIGHLIGHT);
2981 m_aStyles.append(static_cast<sal_Int32>(msfilter::util::TransColToIco(rBrush.GetColor())));
2984 void RtfAttributeOutput::TextINetFormat(const SwFormatINetFormat& rURL)
2986 if (rURL.GetValue().isEmpty())
2987 return;
2989 const SwCharFormat* pFormat;
2990 const SwTextINetFormat* pTextAtr = rURL.GetTextINetFormat();
2992 if (pTextAtr && nullptr != (pFormat = pTextAtr->GetCharFormat()))
2994 sal_uInt16 nStyle = m_rExport.GetId(pFormat);
2995 OString* pString = m_rExport.GetStyle(nStyle);
2996 if (pString)
2997 m_aStyles.append(*pString);
3001 void RtfAttributeOutput::TextCharFormat(const SwFormatCharFormat& rCharFormat)
3003 sal_uInt16 nStyle = m_rExport.GetId(rCharFormat.GetCharFormat());
3004 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_CS);
3005 m_aStyles.append(static_cast<sal_Int32>(nStyle));
3006 OString* pString = m_rExport.GetStyle(nStyle);
3007 if (pString)
3008 m_aStyles.append(*pString);
3011 void RtfAttributeOutput::WriteTextFootnoteNumStr(const SwFormatFootnote& rFootnote)
3013 if (rFootnote.GetNumStr().isEmpty())
3014 m_aRun->append(OOO_STRING_SVTOOLS_RTF_CHFTN);
3015 else
3016 m_aRun->append(
3017 msfilter::rtfutil::OutString(rFootnote.GetNumStr(), m_rExport.GetCurrentEncoding()));
3020 void RtfAttributeOutput::TextFootnote_Impl(const SwFormatFootnote& rFootnote)
3022 SAL_INFO("sw.rtf", __func__ << " start");
3024 m_aRun->append("{" OOO_STRING_SVTOOLS_RTF_SUPER " ");
3025 EndRunProperties(nullptr);
3026 m_aRun->append(' ');
3027 WriteTextFootnoteNumStr(rFootnote);
3028 m_aRun->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FOOTNOTE);
3029 if (rFootnote.IsEndNote() || m_rExport.m_rDoc.GetFootnoteInfo().m_ePos == FTNPOS_CHAPTER)
3030 m_aRun->append(OOO_STRING_SVTOOLS_RTF_FTNALT);
3031 m_aRun->append(' ');
3032 WriteTextFootnoteNumStr(rFootnote);
3035 * The footnote contains a whole paragraph, so we have to:
3036 * 1) Reset, then later restore the contents of our run buffer and run state.
3037 * 2) Buffer the output of the whole paragraph, as we do so for section headers already.
3039 const SwNodeIndex* pIndex = rFootnote.GetTextFootnote()->GetStartNode();
3040 RtfStringBuffer aRun = m_aRun;
3041 m_aRun.clear();
3042 bool bInRunOrig = m_bInRun;
3043 m_bInRun = false;
3044 bool bSingleEmptyRunOrig = m_bSingleEmptyRun;
3045 m_bSingleEmptyRun = false;
3046 m_bBufferSectionHeaders = true;
3047 m_rExport.WriteSpecialText(pIndex->GetIndex() + 1, pIndex->GetNode().EndOfSectionIndex(),
3048 !rFootnote.IsEndNote() ? TXT_FTN : TXT_EDN);
3049 m_bBufferSectionHeaders = false;
3050 m_bInRun = bInRunOrig;
3051 m_bSingleEmptyRun = bSingleEmptyRunOrig;
3052 m_aRun = aRun;
3053 m_aRun->append(m_aSectionHeaders);
3054 m_aSectionHeaders.setLength(0);
3056 m_aRun->append("}");
3057 m_aRun->append("}");
3059 SAL_INFO("sw.rtf", __func__ << " end");
3062 void RtfAttributeOutput::ParaLineSpacing_Impl(short nSpace, short nMulti)
3064 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SL);
3065 m_aStyles.append(static_cast<sal_Int32>(nSpace));
3066 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SLMULT);
3067 m_aStyles.append(static_cast<sal_Int32>(nMulti));
3070 void RtfAttributeOutput::ParaAdjust(const SvxAdjustItem& rAdjust)
3072 switch (rAdjust.GetAdjust())
3074 case SvxAdjust::Left:
3075 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_QL);
3076 break;
3077 case SvxAdjust::Right:
3078 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_QR);
3079 break;
3080 case SvxAdjust::BlockLine:
3081 case SvxAdjust::Block:
3082 if (rAdjust.GetLastBlock() == SvxAdjust::Block)
3083 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_QD);
3084 else
3085 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_QJ);
3086 break;
3087 case SvxAdjust::Center:
3088 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_QC);
3089 break;
3090 default:
3091 break;
3095 void RtfAttributeOutput::ParaSplit(const SvxFormatSplitItem& rSplit)
3097 if (!rSplit.GetValue())
3098 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_KEEP);
3101 void RtfAttributeOutput::ParaWidows(const SvxWidowsItem& rWidows)
3103 if (rWidows.GetValue())
3104 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_WIDCTLPAR);
3105 else
3106 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_NOWIDCTLPAR);
3109 void RtfAttributeOutput::ParaTabStop(const SvxTabStopItem& rTabStop)
3111 tools::Long nOffset = m_rExport.GetParaTabStopOffset();
3113 for (sal_uInt16 n = 0; n < rTabStop.Count(); n++)
3115 const SvxTabStop& rTS = rTabStop[n];
3116 if (SvxTabAdjust::Default != rTS.GetAdjustment())
3118 const char* pFill = nullptr;
3119 switch (rTS.GetFill())
3121 case cDfltFillChar:
3122 break;
3124 case '.':
3125 pFill = OOO_STRING_SVTOOLS_RTF_TLDOT;
3126 break;
3127 case '_':
3128 pFill = OOO_STRING_SVTOOLS_RTF_TLUL;
3129 break;
3130 case '-':
3131 pFill = OOO_STRING_SVTOOLS_RTF_TLTH;
3132 break;
3133 case '=':
3134 pFill = OOO_STRING_SVTOOLS_RTF_TLEQ;
3135 break;
3136 default:
3137 break;
3139 if (pFill)
3140 m_aStyles.append(pFill);
3142 const char* pAdjStr = nullptr;
3143 switch (rTS.GetAdjustment())
3145 case SvxTabAdjust::Right:
3146 pAdjStr = OOO_STRING_SVTOOLS_RTF_TQR;
3147 break;
3148 case SvxTabAdjust::Decimal:
3149 pAdjStr = OOO_STRING_SVTOOLS_RTF_TQDEC;
3150 break;
3151 case SvxTabAdjust::Center:
3152 pAdjStr = OOO_STRING_SVTOOLS_RTF_TQC;
3153 break;
3154 default:
3155 break;
3157 if (pAdjStr)
3158 m_aStyles.append(pAdjStr);
3159 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_TX);
3160 m_aStyles.append(static_cast<sal_Int32>(rTS.GetTabPos() + nOffset));
3162 else
3164 m_aTabStop.append(OOO_STRING_SVTOOLS_RTF_DEFTAB);
3165 m_aTabStop.append(rTabStop[0].GetTabPos());
3170 void RtfAttributeOutput::ParaHyphenZone(const SvxHyphenZoneItem& rHyphenZone)
3172 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_HYPHPAR);
3173 m_aStyles.append(sal_Int32(rHyphenZone.IsHyphen()));
3176 void RtfAttributeOutput::ParaNumRule_Impl(const SwTextNode* pTextNd, sal_Int32 nLvl,
3177 sal_Int32 nNumId)
3179 if (USHRT_MAX == nNumId || 0 == nNumId || nullptr == pTextNd)
3180 return;
3182 const SwNumRule* pRule = pTextNd->GetNumRule();
3184 if (!pRule || !pTextNd->IsInList())
3185 return;
3187 SAL_WARN_IF(pTextNd->GetActualListLevel() < 0 || pTextNd->GetActualListLevel() >= MAXLEVEL,
3188 "sw.rtf", "text node does not have valid list level");
3190 const SwNumFormat* pFormat = pRule->GetNumFormat(nLvl);
3191 if (!pFormat)
3192 pFormat = &pRule->Get(nLvl);
3194 const SfxItemSet& rNdSet = pTextNd->GetSwAttrSet();
3196 m_aStyles.append('{');
3197 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_LISTTEXT);
3198 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_PARD);
3199 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_PLAIN);
3200 m_aStyles.append(' ');
3202 SvxFirstLineIndentItem firstLine(rNdSet.Get(RES_MARGIN_FIRSTLINE));
3203 SvxTextLeftMarginItem leftMargin(rNdSet.Get(RES_MARGIN_TEXTLEFT));
3204 leftMargin.SetTextLeft(leftMargin.GetTextLeft() + pFormat->GetIndentAt());
3205 firstLine.SetTextFirstLineOffset(pFormat->GetFirstLineOffset()); //TODO: overflow
3207 sal_uInt16 nStyle = m_rExport.GetId(pFormat->GetCharFormat());
3208 OString* pString = m_rExport.GetStyle(nStyle);
3209 if (pString)
3210 m_aStyles.append(*pString);
3213 OUString sText;
3214 if (SVX_NUM_CHAR_SPECIAL == pFormat->GetNumberingType()
3215 || SVX_NUM_BITMAP == pFormat->GetNumberingType())
3217 sal_UCS4 cBullet = pFormat->GetBulletChar();
3218 sText = OUString(&cBullet, 1);
3220 else
3221 sText = pTextNd->GetNumString();
3223 if (!sText.isEmpty())
3225 m_aStyles.append(' ');
3226 m_aStyles.append(msfilter::rtfutil::OutString(sText, m_rExport.GetDefaultEncoding()));
3229 if (OUTLINE_RULE != pRule->GetRuleType())
3231 if (!sText.isEmpty())
3232 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_TAB);
3233 m_aStyles.append('}');
3234 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ILVL);
3235 if (nLvl > 8) // RTF knows only 9 levels
3237 m_aStyles.append(sal_Int32(8));
3238 m_aStyles.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_SOUTLVL);
3239 m_aStyles.append(nLvl);
3240 m_aStyles.append('}');
3242 else
3243 m_aStyles.append(nLvl);
3245 else
3246 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_TAB "}");
3247 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_LS);
3248 m_aStyles.append(static_cast<sal_Int32>(m_rExport.GetNumberingId(*pRule)) + 1);
3249 m_aStyles.append(' ');
3251 FormatFirstLineIndent(firstLine);
3252 FormatTextLeftMargin(leftMargin);
3255 void RtfAttributeOutput::ParaScriptSpace(const SfxBoolItem& rScriptSpace)
3257 if (!rScriptSpace.GetValue())
3258 return;
3260 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ASPALPHA);
3263 void RtfAttributeOutput::ParaHangingPunctuation(const SfxBoolItem& /*rItem*/)
3265 SAL_INFO("sw.rtf", "TODO: " << __func__);
3268 void RtfAttributeOutput::ParaForbiddenRules(const SfxBoolItem& /*rItem*/)
3270 SAL_INFO("sw.rtf", "TODO: " << __func__);
3273 void RtfAttributeOutput::ParaVerticalAlign(const SvxParaVertAlignItem& rAlign)
3275 const char* pStr;
3276 switch (rAlign.GetValue())
3278 case SvxParaVertAlignItem::Align::Top:
3279 pStr = OOO_STRING_SVTOOLS_RTF_FAHANG;
3280 break;
3281 case SvxParaVertAlignItem::Align::Bottom:
3282 pStr = OOO_STRING_SVTOOLS_RTF_FAVAR;
3283 break;
3284 case SvxParaVertAlignItem::Align::Center:
3285 pStr = OOO_STRING_SVTOOLS_RTF_FACENTER;
3286 break;
3287 case SvxParaVertAlignItem::Align::Baseline:
3288 pStr = OOO_STRING_SVTOOLS_RTF_FAROMAN;
3289 break;
3291 default:
3292 pStr = OOO_STRING_SVTOOLS_RTF_FAAUTO;
3293 break;
3295 m_aStyles.append(pStr);
3298 void RtfAttributeOutput::ParaSnapToGrid(const SvxParaGridItem& /*rGrid*/)
3300 SAL_INFO("sw.rtf", "TODO: " << __func__);
3303 void RtfAttributeOutput::FormatFrameSize(const SwFormatFrameSize& rSize)
3305 if (m_rExport.m_bOutPageDescs)
3307 m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_PGWSXN);
3308 m_aSectionBreaks.append(static_cast<sal_Int32>(rSize.GetWidth()));
3309 m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_PGHSXN);
3310 m_aSectionBreaks.append(static_cast<sal_Int32>(rSize.GetHeight()));
3311 if (!m_bBufferSectionBreaks)
3313 m_rExport.Strm().WriteOString(m_aSectionBreaks);
3314 m_aSectionBreaks.setLength(0);
3319 void RtfAttributeOutput::FormatPaperBin(const SvxPaperBinItem& /*rItem*/)
3321 SAL_INFO("sw.rtf", "TODO: " << __func__);
3324 void RtfAttributeOutput::FormatFirstLineIndent(SvxFirstLineIndentItem const& rFirstLine)
3326 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_FI);
3327 m_aStyles.append(static_cast<sal_Int32>(rFirstLine.GetTextFirstLineOffset()));
3330 void RtfAttributeOutput::FormatTextLeftMargin(SvxTextLeftMarginItem const& rTextLeftMargin)
3332 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_LI);
3333 m_aStyles.append(static_cast<sal_Int32>(rTextLeftMargin.GetTextLeft()));
3334 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_LIN);
3335 m_aStyles.append(static_cast<sal_Int32>(rTextLeftMargin.GetTextLeft()));
3338 void RtfAttributeOutput::FormatRightMargin(SvxRightMarginItem const& rRightMargin)
3340 // (paragraph case, this will be an else branch once others are converted)
3341 #if 0
3342 else
3343 #endif
3345 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_RI);
3346 m_aStyles.append(static_cast<sal_Int32>(rRightMargin.GetRight()));
3347 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_RIN);
3348 m_aStyles.append(static_cast<sal_Int32>(rRightMargin.GetRight()));
3352 void RtfAttributeOutput::FormatLRSpace(const SvxLRSpaceItem& rLRSpace)
3354 if (!m_rExport.m_bOutFlyFrameAttrs)
3356 if (m_rExport.m_bOutPageDescs)
3358 m_aPageMargins.nLeft = 0;
3359 m_aPageMargins.nRight = 0;
3361 if (const SvxBoxItem* pBoxItem = m_rExport.HasItem(RES_BOX))
3363 m_aPageMargins.nLeft
3364 = pBoxItem->CalcLineSpace(SvxBoxItemLine::LEFT, /*bEvenIfNoLine*/ true);
3365 m_aPageMargins.nRight
3366 = pBoxItem->CalcLineSpace(SvxBoxItemLine::RIGHT, /*bEvenIfNoLine*/ true);
3369 m_aPageMargins.nLeft += sal::static_int_cast<sal_uInt16>(rLRSpace.GetLeft());
3370 m_aPageMargins.nRight += sal::static_int_cast<sal_uInt16>(rLRSpace.GetRight());
3372 if (rLRSpace.GetLeft())
3374 m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_MARGLSXN);
3375 m_aSectionBreaks.append(static_cast<sal_Int32>(m_aPageMargins.nLeft));
3377 if (rLRSpace.GetRight())
3379 m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_MARGRSXN);
3380 m_aSectionBreaks.append(static_cast<sal_Int32>(m_aPageMargins.nRight));
3382 if (rLRSpace.GetGutterMargin())
3384 m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_GUTTER);
3385 m_aSectionBreaks.append(static_cast<sal_Int32>(rLRSpace.GetGutterMargin()));
3387 if (!m_bBufferSectionBreaks)
3389 m_rExport.Strm().WriteOString(m_aSectionBreaks);
3390 m_aSectionBreaks.setLength(0);
3393 else
3395 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_LI);
3396 m_aStyles.append(static_cast<sal_Int32>(rLRSpace.GetTextLeft()));
3397 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_RI);
3398 m_aStyles.append(static_cast<sal_Int32>(rLRSpace.GetRight()));
3399 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_LIN);
3400 m_aStyles.append(static_cast<sal_Int32>(rLRSpace.GetTextLeft()));
3401 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_RIN);
3402 m_aStyles.append(static_cast<sal_Int32>(rLRSpace.GetRight()));
3403 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_FI);
3404 m_aStyles.append(static_cast<sal_Int32>(rLRSpace.GetTextFirstLineOffset()));
3407 else if (m_rExport.GetRTFFlySyntax())
3409 // Wrap: top and bottom spacing, convert from twips to EMUs.
3410 m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3411 "dxWrapDistLeft", OString::number(o3tl::convert(rLRSpace.GetLeft(), o3tl::Length::twip,
3412 o3tl::Length::emu))));
3413 m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3414 "dxWrapDistRight", OString::number(o3tl::convert(
3415 rLRSpace.GetRight(), o3tl::Length::twip, o3tl::Length::emu))));
3419 void RtfAttributeOutput::FormatULSpace(const SvxULSpaceItem& rULSpace)
3421 if (!m_rExport.m_bOutFlyFrameAttrs)
3423 if (m_rExport.m_bOutPageDescs)
3425 OSL_ENSURE(m_rExport.GetCurItemSet(), "Impossible");
3426 if (!m_rExport.GetCurItemSet())
3427 return;
3429 // If we export a follow page format, then our doc model has
3430 // separate header/footer distances for the first page and the
3431 // follow pages, but Word can have only a single distance. In case
3432 // the two values differ, work with the value from the first page
3433 // format to be in sync with the import.
3434 sw::util::HdFtDistanceGlue aDistances(m_rExport.GetFirstPageItemSet()
3435 ? *m_rExport.GetFirstPageItemSet()
3436 : *m_rExport.GetCurItemSet());
3438 if (aDistances.m_DyaTop)
3440 m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_MARGTSXN);
3441 m_aSectionBreaks.append(static_cast<sal_Int32>(aDistances.m_DyaTop));
3442 m_aPageMargins.nTop = aDistances.m_DyaTop;
3444 if (aDistances.HasHeader())
3446 m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_HEADERY);
3447 m_aSectionBreaks.append(static_cast<sal_Int32>(aDistances.m_DyaHdrTop));
3450 if (aDistances.m_DyaBottom)
3452 m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_MARGBSXN);
3453 m_aSectionBreaks.append(static_cast<sal_Int32>(aDistances.m_DyaBottom));
3454 m_aPageMargins.nBottom = aDistances.m_DyaBottom;
3456 if (aDistances.HasFooter())
3458 m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_FOOTERY);
3459 m_aSectionBreaks.append(static_cast<sal_Int32>(aDistances.m_DyaHdrBottom));
3461 if (!m_bBufferSectionBreaks)
3463 m_rExport.Strm().WriteOString(m_aSectionBreaks);
3464 m_aSectionBreaks.setLength(0);
3467 else
3469 // Spacing before.
3470 if (m_bParaBeforeAutoSpacing && m_nParaBeforeSpacing == rULSpace.GetUpper())
3471 m_aStyles.append(LO_STRING_SVTOOLS_RTF_SBAUTO "1");
3472 else if (m_bParaBeforeAutoSpacing && m_nParaBeforeSpacing == -1)
3474 m_aStyles.append(LO_STRING_SVTOOLS_RTF_SBAUTO "0");
3475 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SB);
3476 m_aStyles.append(static_cast<sal_Int32>(rULSpace.GetUpper()));
3478 else
3480 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SB);
3481 m_aStyles.append(static_cast<sal_Int32>(rULSpace.GetUpper()));
3483 m_bParaBeforeAutoSpacing = false;
3485 // Spacing after.
3486 if (m_bParaAfterAutoSpacing && m_nParaAfterSpacing == rULSpace.GetLower())
3487 m_aStyles.append(LO_STRING_SVTOOLS_RTF_SAAUTO "1");
3488 else if (m_bParaAfterAutoSpacing && m_nParaAfterSpacing == -1)
3490 m_aStyles.append(LO_STRING_SVTOOLS_RTF_SAAUTO "0");
3491 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SA);
3492 m_aStyles.append(static_cast<sal_Int32>(rULSpace.GetLower()));
3494 else
3496 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SA);
3497 m_aStyles.append(static_cast<sal_Int32>(rULSpace.GetLower()));
3499 m_bParaAfterAutoSpacing = false;
3501 // Contextual spacing.
3502 if (rULSpace.GetContext())
3503 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_CONTEXTUALSPACE);
3506 else if (m_rExport.GetRTFFlySyntax())
3508 // Wrap: top and bottom spacing, convert from twips to EMUs.
3509 m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3510 "dyWrapDistTop", OString::number(o3tl::convert(rULSpace.GetUpper(), o3tl::Length::twip,
3511 o3tl::Length::emu))));
3512 m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3513 "dyWrapDistBottom", OString::number(o3tl::convert(
3514 rULSpace.GetLower(), o3tl::Length::twip, o3tl::Length::emu))));
3518 void RtfAttributeOutput::FormatSurround(const SwFormatSurround& rSurround)
3520 if (m_rExport.m_bOutFlyFrameAttrs && !m_rExport.GetRTFFlySyntax())
3522 css::text::WrapTextMode eSurround = rSurround.GetSurround();
3523 bool bGold = css::text::WrapTextMode_DYNAMIC == eSurround;
3524 if (bGold)
3525 eSurround = css::text::WrapTextMode_PARALLEL;
3526 RTFSurround aMC(bGold, static_cast<sal_uInt8>(eSurround));
3527 m_aRunText->append(OOO_STRING_SVTOOLS_RTF_FLYMAINCNT);
3528 m_aRunText->append(static_cast<sal_Int32>(aMC.GetValue()));
3530 else if (m_rExport.m_bOutFlyFrameAttrs && m_rExport.GetRTFFlySyntax())
3532 // See DocxSdrExport::startDMLAnchorInline() for SwFormatSurround -> WR / WRK mappings.
3533 sal_Int32 nWr = -1;
3534 std::optional<sal_Int32> oWrk;
3535 switch (rSurround.GetValue())
3537 case css::text::WrapTextMode_NONE:
3538 nWr = 1; // top and bottom
3539 break;
3540 case css::text::WrapTextMode_THROUGH:
3541 nWr = 3; // none
3542 break;
3543 case css::text::WrapTextMode_PARALLEL:
3544 nWr = 2; // around
3545 oWrk = 0; // both sides
3546 break;
3547 case css::text::WrapTextMode_DYNAMIC:
3548 default:
3549 nWr = 2; // around
3550 oWrk = 3; // largest
3551 break;
3554 if (rSurround.IsContour())
3555 nWr = 4; // tight
3557 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_SHPWR);
3558 m_rExport.Strm().WriteNumberAsString(nWr);
3559 if (oWrk)
3561 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_SHPWRK);
3562 m_rExport.Strm().WriteNumberAsString(*oWrk);
3567 void RtfAttributeOutput::FormatVertOrientation(const SwFormatVertOrient& rFlyVert)
3569 if (!(m_rExport.m_bOutFlyFrameAttrs && m_rExport.GetRTFFlySyntax()))
3570 return;
3572 switch (rFlyVert.GetRelationOrient())
3574 case text::RelOrientation::PAGE_FRAME:
3575 m_aFlyProperties.push_back(
3576 std::make_pair<OString, OString>("posrelv", OString::number(1)));
3577 break;
3578 default:
3579 m_aFlyProperties.push_back(
3580 std::make_pair<OString, OString>("posrelv", OString::number(2)));
3581 m_rExport.Strm()
3582 .WriteOString(OOO_STRING_SVTOOLS_RTF_SHPBYPARA)
3583 .WriteOString(OOO_STRING_SVTOOLS_RTF_SHPBYIGNORE);
3584 break;
3587 switch (rFlyVert.GetVertOrient())
3589 case text::VertOrientation::TOP:
3590 case text::VertOrientation::LINE_TOP:
3591 m_aFlyProperties.push_back(
3592 std::make_pair<OString, OString>("posv", OString::number(1)));
3593 break;
3594 case text::VertOrientation::BOTTOM:
3595 case text::VertOrientation::LINE_BOTTOM:
3596 m_aFlyProperties.push_back(
3597 std::make_pair<OString, OString>("posv", OString::number(3)));
3598 break;
3599 case text::VertOrientation::CENTER:
3600 case text::VertOrientation::LINE_CENTER:
3601 m_aFlyProperties.push_back(
3602 std::make_pair<OString, OString>("posv", OString::number(2)));
3603 break;
3604 default:
3605 break;
3608 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_SHPTOP);
3609 m_rExport.Strm().WriteNumberAsString(rFlyVert.GetPos());
3610 if (m_pFlyFrameSize)
3612 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_SHPBOTTOM);
3613 m_rExport.Strm().WriteNumberAsString(rFlyVert.GetPos() + m_pFlyFrameSize->Height());
3617 void RtfAttributeOutput::FormatHorizOrientation(const SwFormatHoriOrient& rFlyHori)
3619 if (!(m_rExport.m_bOutFlyFrameAttrs && m_rExport.GetRTFFlySyntax()))
3620 return;
3622 switch (rFlyHori.GetRelationOrient())
3624 case text::RelOrientation::PAGE_FRAME:
3625 m_aFlyProperties.push_back(
3626 std::make_pair<OString, OString>("posrelh", OString::number(1)));
3627 break;
3628 default:
3629 m_aFlyProperties.push_back(
3630 std::make_pair<OString, OString>("posrelh", OString::number(2)));
3631 m_rExport.Strm()
3632 .WriteOString(OOO_STRING_SVTOOLS_RTF_SHPBXCOLUMN)
3633 .WriteOString(OOO_STRING_SVTOOLS_RTF_SHPBXIGNORE);
3634 break;
3637 switch (rFlyHori.GetHoriOrient())
3639 case text::HoriOrientation::LEFT:
3640 m_aFlyProperties.push_back(
3641 std::make_pair<OString, OString>("posh", OString::number(1)));
3642 break;
3643 case text::HoriOrientation::CENTER:
3644 m_aFlyProperties.push_back(
3645 std::make_pair<OString, OString>("posh", OString::number(2)));
3646 break;
3647 case text::HoriOrientation::RIGHT:
3648 m_aFlyProperties.push_back(
3649 std::make_pair<OString, OString>("posh", OString::number(3)));
3650 break;
3651 default:
3652 break;
3655 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_SHPLEFT);
3656 m_rExport.Strm().WriteNumberAsString(rFlyHori.GetPos());
3657 if (m_pFlyFrameSize)
3659 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_SHPRIGHT);
3660 m_rExport.Strm().WriteNumberAsString(rFlyHori.GetPos() + m_pFlyFrameSize->Width());
3664 void RtfAttributeOutput::FormatAnchor(const SwFormatAnchor& rAnchor)
3666 if (m_rExport.GetRTFFlySyntax())
3667 return;
3669 RndStdIds eId = rAnchor.GetAnchorId();
3670 m_aRunText->append(OOO_STRING_SVTOOLS_RTF_FLYANCHOR);
3671 m_aRunText->append(static_cast<sal_Int32>(eId));
3672 switch (eId)
3674 case RndStdIds::FLY_AT_PAGE:
3675 m_aRunText->append(OOO_STRING_SVTOOLS_RTF_FLYPAGE);
3676 m_aRunText->append(static_cast<sal_Int32>(rAnchor.GetPageNum()));
3677 break;
3678 case RndStdIds::FLY_AT_PARA:
3679 case RndStdIds::FLY_AS_CHAR:
3680 m_aRunText->append(OOO_STRING_SVTOOLS_RTF_FLYCNTNT);
3681 break;
3682 default:
3683 break;
3687 void RtfAttributeOutput::FormatBackground(const SvxBrushItem& rBrush)
3689 if (m_rExport.GetRTFFlySyntax())
3691 const Color& rColor = rBrush.GetColor();
3692 // We in fact need RGB to BGR, but the transformation is symmetric.
3693 m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3694 "fillColor", OString::number(wwUtility::RGBToBGR(rColor))));
3696 else if (!rBrush.GetColor().IsTransparent())
3698 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_CBPAT);
3699 m_aStyles.append(static_cast<sal_Int32>(m_rExport.GetColor(rBrush.GetColor())));
3703 void RtfAttributeOutput::FormatFillStyle(const XFillStyleItem& rFillStyle)
3705 m_oFillStyle = rFillStyle.GetValue();
3708 void RtfAttributeOutput::FormatFillGradient(const XFillGradientItem& rFillGradient)
3710 if (*m_oFillStyle != drawing::FillStyle_GRADIENT)
3711 return;
3713 m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3714 "fillType", OString::number(7))); // Shade using the fillAngle
3716 const basegfx::BGradient& rGradient(rFillGradient.GetGradientValue());
3717 const basegfx::BColorStops& rColorStops(rGradient.GetColorStops());
3719 // MCGR: It would be best to export the full MCGR definition here
3720 // with all ColorStops in rColorStops, but rtf does not support this.
3721 // Best thing to do and to stay compatible is to export front/back
3722 // colors as start/end and - when more than two ColorStops are defined -
3723 // guess that GradientStyle_AXIAL is used and thus create a "fillFocus"
3724 // entry
3725 // NOTE: I also found that loading file from testTextframeGradient
3726 // "textframe-gradient.rtf" and save-as *inverts* the gradient, so I
3727 // exchanged here fillColor/fillBackColor to get the correct order
3728 const Color aStartColor(rColorStops.front().getStopColor());
3729 m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3730 "fillColor", OString::number(wwUtility::RGBToBGR(aStartColor))));
3732 if (rColorStops.size() < 3)
3734 // two-color version, use back as 2nd color
3735 const Color aEndColor(rColorStops.back().getStopColor());
3736 m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3737 "fillBackColor", OString::number(wwUtility::RGBToBGR(aEndColor))));
3739 else
3741 // assume what was formally GradientStyle_AXIAL, see above and also refer to
3742 // FillModel::pushToPropMap 'fFocus' value and usage.
3743 // The 2nd color is the in-between color, use it
3744 const Color aEndColor(rColorStops[1].getStopColor());
3745 m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3746 "fillBackColor", OString::number(wwUtility::RGBToBGR(aEndColor))));
3747 m_aFlyProperties.push_back(
3748 std::make_pair<OString, OString>("fillFocus", OString::number(50)));
3752 void RtfAttributeOutput::FormatBox(const SvxBoxItem& rBox)
3754 static const SvxBoxItemLine aBorders[] = { SvxBoxItemLine::TOP, SvxBoxItemLine::LEFT,
3755 SvxBoxItemLine::BOTTOM, SvxBoxItemLine::RIGHT };
3756 static const char* aBorderNames[]
3757 = { OOO_STRING_SVTOOLS_RTF_BRDRT, OOO_STRING_SVTOOLS_RTF_BRDRL,
3758 OOO_STRING_SVTOOLS_RTF_BRDRB, OOO_STRING_SVTOOLS_RTF_BRDRR };
3760 sal_uInt16 const nDist = rBox.GetSmallestDistance();
3762 if (m_rExport.GetRTFFlySyntax())
3764 // Borders: spacing to contents, convert from twips to EMUs.
3765 m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3766 "dxTextLeft", OString::number(o3tl::convert(rBox.GetDistance(SvxBoxItemLine::LEFT),
3767 o3tl::Length::twip, o3tl::Length::emu))));
3768 m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3769 "dyTextTop", OString::number(o3tl::convert(rBox.GetDistance(SvxBoxItemLine::TOP),
3770 o3tl::Length::twip, o3tl::Length::emu))));
3771 m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3772 "dxTextRight", OString::number(o3tl::convert(rBox.GetDistance(SvxBoxItemLine::RIGHT),
3773 o3tl::Length::twip, o3tl::Length::emu))));
3774 m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3775 "dyTextBottom", OString::number(o3tl::convert(rBox.GetDistance(SvxBoxItemLine::BOTTOM),
3776 o3tl::Length::twip, o3tl::Length::emu))));
3778 const editeng::SvxBorderLine* pLeft = rBox.GetLine(SvxBoxItemLine::LEFT);
3779 const editeng::SvxBorderLine* pRight = rBox.GetLine(SvxBoxItemLine::RIGHT);
3780 const editeng::SvxBorderLine* pTop = rBox.GetLine(SvxBoxItemLine::TOP);
3781 const editeng::SvxBorderLine* pBottom = rBox.GetLine(SvxBoxItemLine::BOTTOM);
3783 if (!pLeft && !pRight && !pBottom && !pTop)
3785 // fLine has default 'true', so need to write it out in case of no border.
3786 m_aFlyProperties.push_back(std::make_pair<OString, OString>("fLine", "0"));
3787 return;
3790 // RTF has the flags fTopLine, fBottomLine, fLeftLine and fRightLine to disable single border
3791 // lines. But Word cannot disable single border lines. So we do not use them. In case of
3792 // single border lines it is better to draw all four borders than drawing none. So we look
3793 // whether a border line exists, which is effectively drawn.
3794 const editeng::SvxBorderLine* pBorder = nullptr;
3795 if (pTop && pTop->GetBorderLineStyle() != SvxBorderLineStyle::NONE)
3796 pBorder = pTop;
3797 else if (pBottom && pBottom->GetBorderLineStyle() != SvxBorderLineStyle::NONE)
3798 pBorder = pBottom;
3799 else if (pLeft && pLeft->GetBorderLineStyle() != SvxBorderLineStyle::NONE)
3800 pBorder = pLeft;
3801 else if (pRight && pRight->GetBorderLineStyle() != SvxBorderLineStyle::NONE)
3802 pBorder = pRight;
3804 if (!pBorder)
3806 m_aFlyProperties.push_back(std::make_pair<OString, OString>("fLine", "0"));
3807 return;
3810 const Color& rColor = pBorder->GetColor();
3811 // We in fact need RGB to BGR, but the transformation is symmetric.
3812 m_aFlyProperties.push_back(std::make_pair<OString, OString>(
3813 "lineColor", OString::number(wwUtility::RGBToBGR(rColor))));
3815 double const fConverted(
3816 editeng::ConvertBorderWidthToWord(pBorder->GetBorderLineStyle(), pBorder->GetWidth()));
3817 sal_Int32 nWidth = o3tl::convert(fConverted, o3tl::Length::twip, o3tl::Length::emu);
3818 m_aFlyProperties.push_back(
3819 std::make_pair<OString, OString>("lineWidth", OString::number(nWidth)));
3821 return;
3824 if (rBox.GetTop() && rBox.GetBottom() && rBox.GetLeft() && rBox.GetRight()
3825 && *rBox.GetTop() == *rBox.GetBottom() && *rBox.GetTop() == *rBox.GetLeft()
3826 && *rBox.GetTop() == *rBox.GetRight() && nDist == rBox.GetDistance(SvxBoxItemLine::TOP)
3827 && nDist == rBox.GetDistance(SvxBoxItemLine::LEFT)
3828 && nDist == rBox.GetDistance(SvxBoxItemLine::BOTTOM)
3829 && nDist == rBox.GetDistance(SvxBoxItemLine::RIGHT))
3830 m_aSectionBreaks.append(
3831 OutBorderLine(m_rExport, rBox.GetTop(), OOO_STRING_SVTOOLS_RTF_BOX, nDist));
3832 else
3834 SvxShadowLocation eShadowLocation = SvxShadowLocation::NONE;
3835 if (const SvxShadowItem* pItem = GetExport().HasItem(RES_SHADOW))
3836 eShadowLocation = pItem->GetLocation();
3838 const SvxBoxItemLine* pBrd = aBorders;
3839 const char** pBrdNms = aBorderNames;
3840 for (int i = 0; i < 4; ++i, ++pBrd, ++pBrdNms)
3842 editeng::SvxBorderLine const* const pLn = rBox.GetLine(*pBrd);
3843 m_aSectionBreaks.append(
3844 OutBorderLine(m_rExport, pLn, *pBrdNms, rBox.GetDistance(*pBrd), eShadowLocation));
3848 if (!m_bBufferSectionBreaks)
3850 m_aStyles.append(m_aSectionBreaks);
3851 m_aSectionBreaks.setLength(0);
3855 void RtfAttributeOutput::FormatColumns_Impl(sal_uInt16 nCols, const SwFormatCol& rCol, bool bEven,
3856 SwTwips nPageSize)
3858 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_COLS);
3859 m_rExport.Strm().WriteNumberAsString(nCols);
3861 if (rCol.GetLineAdj() != COLADJ_NONE)
3862 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_LINEBETCOL);
3864 if (bEven)
3866 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_COLSX);
3867 m_rExport.Strm().WriteNumberAsString(rCol.GetGutterWidth(true));
3869 else
3871 const SwColumns& rColumns = rCol.GetColumns();
3872 for (sal_uInt16 n = 0; n < nCols;)
3874 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_COLNO);
3875 m_rExport.Strm().WriteNumberAsString(n + 1);
3877 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_COLW);
3878 m_rExport.Strm().WriteNumberAsString(rCol.CalcPrtColWidth(n, nPageSize));
3880 if (++n != nCols)
3882 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_COLSR);
3883 m_rExport.Strm().WriteNumberAsString(rColumns[n - 1].GetRight()
3884 + rColumns[n].GetLeft());
3890 void RtfAttributeOutput::FormatKeep(const SvxFormatKeepItem& rItem)
3892 if (rItem.GetValue())
3893 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_KEEPN);
3896 void RtfAttributeOutput::FormatTextGrid(const SwTextGridItem& /*rGrid*/)
3898 SAL_INFO("sw.rtf", "TODO: " << __func__);
3901 void RtfAttributeOutput::FormatLineNumbering(const SwFormatLineNumber& rNumbering)
3903 if (!rNumbering.IsCount())
3904 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_NOLINE);
3907 void RtfAttributeOutput::FormatFrameDirection(const SvxFrameDirectionItem& rDirection)
3909 SvxFrameDirection nDir = rDirection.GetValue();
3910 if (nDir == SvxFrameDirection::Environment)
3911 nDir = GetExport().GetDefaultFrameDirection();
3913 if (m_rExport.m_bOutPageDescs)
3915 if (nDir == SvxFrameDirection::Vertical_RL_TB)
3917 m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_STEXTFLOW);
3918 m_aSectionBreaks.append(static_cast<sal_Int32>(1));
3919 if (!m_bBufferSectionBreaks)
3921 m_rExport.Strm().WriteOString(m_aSectionBreaks);
3922 m_aSectionBreaks.setLength(0);
3925 return;
3928 if (m_rExport.GetRTFFlySyntax())
3930 if (nDir == SvxFrameDirection::Vertical_RL_TB)
3932 // Top to bottom non-ASCII font
3933 m_aFlyProperties.push_back(std::make_pair<OString, OString>("txflTextFlow", "3"));
3935 else if (rDirection.GetValue() == SvxFrameDirection::Vertical_LR_BT)
3937 // Bottom to top non-ASCII font
3938 m_aFlyProperties.push_back(std::make_pair<OString, OString>("txflTextFlow", "2"));
3940 return;
3943 if (nDir == SvxFrameDirection::Horizontal_RL_TB)
3944 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_RTLPAR);
3945 else
3946 m_aStyles.append(OOO_STRING_SVTOOLS_RTF_LTRPAR);
3949 void RtfAttributeOutput::ParaGrabBag(const SfxGrabBagItem& rItem)
3951 const std::map<OUString, css::uno::Any>& rMap = rItem.GetGrabBag();
3952 for (const auto& rValue : rMap)
3954 if (rValue.first == "ParaTopMarginBeforeAutoSpacing")
3956 m_bParaBeforeAutoSpacing = true;
3957 rValue.second >>= m_nParaBeforeSpacing;
3958 m_nParaBeforeSpacing = o3tl::toTwips(m_nParaBeforeSpacing, o3tl::Length::mm100);
3960 else if (rValue.first == "ParaBottomMarginAfterAutoSpacing")
3962 m_bParaAfterAutoSpacing = true;
3963 rValue.second >>= m_nParaAfterSpacing;
3964 m_nParaAfterSpacing = o3tl::toTwips(m_nParaAfterSpacing, o3tl::Length::mm100);
3969 void RtfAttributeOutput::CharGrabBag(const SfxGrabBagItem& /*rItem*/) {}
3971 void RtfAttributeOutput::ParaOutlineLevel(const SfxUInt16Item& /*rItem*/) {}
3973 void RtfAttributeOutput::WriteExpand(const SwField* pField)
3975 OUString sCmd; // for optional Parameters
3976 switch (pField->GetTyp()->Which())
3978 //#i119803# Export user field for RTF filter
3979 case SwFieldIds::User:
3980 sCmd = pField->GetTyp()->GetName();
3981 m_rExport.OutputField(pField, ww::eNONE, sCmd);
3982 break;
3983 default:
3984 m_rExport.OutputField(pField, ww::eUNKNOWN, sCmd);
3985 break;
3989 void RtfAttributeOutput::RefField(const SwField& /*rField*/, const OUString& /*rRef*/)
3991 SAL_INFO("sw.rtf", "TODO: " << __func__);
3994 void RtfAttributeOutput::HiddenField(const SwField& /*rField*/)
3996 SAL_INFO("sw.rtf", "TODO: " << __func__);
3999 void RtfAttributeOutput::SetField(const SwField& /*rField*/, ww::eField /*eType*/,
4000 const OUString& /*rCmd*/)
4002 SAL_INFO("sw.rtf", "TODO: " << __func__);
4005 void RtfAttributeOutput::PostitField(const SwField* pField)
4007 const SwPostItField& rPField = *static_cast<const SwPostItField*>(pField);
4009 OString aName = OUStringToOString(rPField.GetName(), RTL_TEXTENCODING_UTF8);
4010 auto it = m_rOpenedAnnotationMarksIds.find(aName);
4011 if (it != m_rOpenedAnnotationMarksIds.end())
4013 // In case this field is inside annotation marks, we want to write the
4014 // annotation itself after the annotation mark is closed, not here.
4015 m_aPostitFields[it->second] = &rPField;
4016 return;
4019 m_aRunText->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_ATNID " ");
4020 m_aRunText->append(OUStringToOString(rPField.GetInitials(), m_rExport.GetCurrentEncoding()));
4021 m_aRunText->append("}");
4022 m_aRunText->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_ATNAUTHOR " ");
4023 m_aRunText->append(OUStringToOString(rPField.GetPar1(), m_rExport.GetCurrentEncoding()));
4024 m_aRunText->append("}");
4025 m_aRunText->append(OOO_STRING_SVTOOLS_RTF_CHATN);
4027 m_aRunText->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_ANNOTATION);
4029 if (m_nCurrentAnnotationMarkId != -1)
4031 m_aRunText->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_ATNREF " ");
4032 m_aRunText->append(m_nCurrentAnnotationMarkId);
4033 m_aRunText->append('}');
4035 m_aRunText->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_ATNDATE " ");
4036 m_aRunText->append(static_cast<sal_Int32>(sw::ms::DateTime2DTTM(rPField.GetDateTime())));
4037 m_aRunText->append('}');
4038 if (const OutlinerParaObject* pObject = rPField.GetTextObject())
4039 m_rExport.SdrExporter().WriteOutliner(*pObject, TXT_ATN);
4040 m_aRunText->append('}');
4043 bool RtfAttributeOutput::DropdownField(const SwField* /*pField*/)
4045 // this is handled in OutputFlyFrame_Impl()
4046 return true;
4049 bool RtfAttributeOutput::PlaceholderField(const SwField* pField)
4051 m_aRunText->append("{" OOO_STRING_SVTOOLS_RTF_FIELD
4052 "{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FLDINST
4053 " MACROBUTTON None ");
4054 RunText(pField->GetPar1());
4055 m_aRunText->append("}}");
4056 return false; // do not expand
4059 RtfAttributeOutput::RtfAttributeOutput(RtfExport& rExport)
4060 : AttributeOutputBase("") // ConvertURL isn't used now in RTF output
4061 , m_rExport(rExport)
4062 , m_pPrevPageDesc(nullptr)
4063 , m_nStyleId(0)
4064 , m_nListId(0)
4065 , m_bIsRTL(false)
4066 , m_nScript(i18n::ScriptType::LATIN)
4067 , m_bControlLtrRtl(false)
4068 , m_nNextAnnotationMarkId(0)
4069 , m_nCurrentAnnotationMarkId(-1)
4070 , m_bTableCellOpen(false)
4071 , m_nTableDepth(0)
4072 , m_bTableAfterCell(false)
4073 , m_nColBreakNeeded(false)
4074 , m_bBufferSectionBreaks(false)
4075 , m_bBufferSectionHeaders(false)
4076 , m_bLastTable(true)
4077 , m_bWroteCellInfo(false)
4078 , m_bTableRowEnded(false)
4079 , m_bIsBeforeFirstParagraph(true)
4080 , m_bSingleEmptyRun(false)
4081 , m_bInRun(false)
4082 , m_bInRuby(false)
4083 , m_pFlyFrameSize(nullptr)
4084 , m_bParaBeforeAutoSpacing(false)
4085 , m_nParaBeforeSpacing(0)
4086 , m_bParaAfterAutoSpacing(false)
4087 , m_nParaAfterSpacing(0)
4091 RtfAttributeOutput::~RtfAttributeOutput() = default;
4093 MSWordExportBase& RtfAttributeOutput::GetExport() { return m_rExport; }
4095 // These are used by wwFont::WriteRtf()
4097 /// Start the font.
4098 void RtfAttributeOutput::StartFont(std::u16string_view rFamilyName) const
4100 // write the font name hex-encoded, but without Unicode - Word at least
4101 // cannot read *both* Unicode and fallback as written by OutString
4102 m_rExport.Strm().WriteOString(
4103 msfilter::rtfutil::OutString(rFamilyName, m_rExport.GetCurrentEncoding(), false));
4106 /// End the font.
4107 void RtfAttributeOutput::EndFont() const
4109 m_rExport.Strm().WriteOString(";}");
4110 m_rExport.SetCurrentEncoding(m_rExport.GetDefaultEncoding());
4113 /// Alternate name for the font.
4114 void RtfAttributeOutput::FontAlternateName(std::u16string_view rName) const
4116 m_rExport.Strm()
4117 .WriteChar('{')
4118 .WriteOString(OOO_STRING_SVTOOLS_RTF_IGNORE)
4119 .WriteOString(OOO_STRING_SVTOOLS_RTF_FALT)
4120 .WriteChar(' ');
4121 // write the font name hex-encoded, but without Unicode - Word at least
4122 // cannot read *both* Unicode and fallback as written by OutString
4123 m_rExport.Strm()
4124 .WriteOString(msfilter::rtfutil::OutString(rName, m_rExport.GetCurrentEncoding(), false))
4125 .WriteChar('}');
4128 /// Font charset.
4129 void RtfAttributeOutput::FontCharset(sal_uInt8 nCharSet) const
4131 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_FCHARSET);
4132 m_rExport.Strm().WriteNumberAsString(nCharSet);
4133 m_rExport.Strm().WriteChar(' ');
4134 m_rExport.SetCurrentEncoding(rtl_getTextEncodingFromWindowsCharset(nCharSet));
4137 /// Font family.
4138 void RtfAttributeOutput::FontFamilyType(FontFamily eFamily, const wwFont& rFont) const
4140 m_rExport.Strm().WriteChar('{').WriteOString(OOO_STRING_SVTOOLS_RTF_F);
4142 const char* pStr = OOO_STRING_SVTOOLS_RTF_FNIL;
4143 switch (eFamily)
4145 case FAMILY_ROMAN:
4146 pStr = OOO_STRING_SVTOOLS_RTF_FROMAN;
4147 break;
4148 case FAMILY_SWISS:
4149 pStr = OOO_STRING_SVTOOLS_RTF_FSWISS;
4150 break;
4151 case FAMILY_MODERN:
4152 pStr = OOO_STRING_SVTOOLS_RTF_FMODERN;
4153 break;
4154 case FAMILY_SCRIPT:
4155 pStr = OOO_STRING_SVTOOLS_RTF_FSCRIPT;
4156 break;
4157 case FAMILY_DECORATIVE:
4158 pStr = OOO_STRING_SVTOOLS_RTF_FDECOR;
4159 break;
4160 default:
4161 break;
4163 m_rExport.Strm().WriteNumberAsString(m_rExport.m_aFontHelper.GetId(rFont)).WriteOString(pStr);
4166 /// Font pitch.
4167 void RtfAttributeOutput::FontPitchType(FontPitch ePitch) const
4169 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_FPRQ);
4171 sal_uInt16 nVal = 0;
4172 switch (ePitch)
4174 case PITCH_FIXED:
4175 nVal = 1;
4176 break;
4177 case PITCH_VARIABLE:
4178 nVal = 2;
4179 break;
4180 default:
4181 break;
4183 m_rExport.Strm().WriteNumberAsString(nVal);
4186 static void lcl_AppendSP(OStringBuffer& rBuffer, std::string_view cName, std::u16string_view rValue,
4187 const RtfExport& rExport)
4189 rBuffer.append("{" OOO_STRING_SVTOOLS_RTF_SP "{"); // "{\sp{"
4190 rBuffer.append(OOO_STRING_SVTOOLS_RTF_SN " "); //" \sn "
4191 rBuffer.append(cName); //"PropName"
4192 rBuffer.append("}{" OOO_STRING_SVTOOLS_RTF_SV " ");
4193 // "}{ \sv "
4194 rBuffer.append(msfilter::rtfutil::OutString(rValue, rExport.GetCurrentEncoding()));
4195 rBuffer.append("}}");
4198 static OString ExportPICT(const SwFlyFrameFormat* pFlyFrameFormat, const Size& rOrig,
4199 const Size& rRendered, const Size& rMapped, const SwCropGrf& rCr,
4200 const char* pBLIPType, const sal_uInt8* pGraphicAry, sal_uInt64 nSize,
4201 const RtfExport& rExport, SvStream* pStream = nullptr,
4202 bool bWritePicProp = true, const SwAttrSet* pAttrSet = nullptr)
4204 OStringBuffer aRet;
4205 if (pBLIPType && nSize && pGraphicAry)
4207 bool bIsWMF = std::strcmp(pBLIPType, OOO_STRING_SVTOOLS_RTF_WMETAFILE) == 0;
4209 aRet.append("{" OOO_STRING_SVTOOLS_RTF_PICT);
4211 if (pFlyFrameFormat && bWritePicProp)
4213 OUString sDescription = pFlyFrameFormat->GetObjDescription();
4214 //write picture properties - wzDescription at first
4215 //looks like: "{\*\picprop{\sp{\sn PropertyName}{\sv PropertyValue}}}"
4216 aRet.append(
4217 "{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_PICPROP); //"{\*\picprop
4218 lcl_AppendSP(aRet, "wzDescription", sDescription, rExport);
4219 OUString sName = pFlyFrameFormat->GetObjTitle();
4220 lcl_AppendSP(aRet, "wzName", sName, rExport);
4222 if (pAttrSet)
4224 MirrorGraph eMirror = pAttrSet->Get(RES_GRFATR_MIRRORGRF).GetValue();
4225 if (eMirror == MirrorGraph::Vertical || eMirror == MirrorGraph::Both)
4226 // Mirror on the vertical axis is a horizontal flip.
4227 lcl_AppendSP(aRet, "fFlipH", u"1", rExport);
4230 aRet.append("}"); //"}"
4233 tools::Long nXCroppedSize = rOrig.Width() - (rCr.GetLeft() + rCr.GetRight());
4234 tools::Long nYCroppedSize = rOrig.Height() - (rCr.GetTop() + rCr.GetBottom());
4235 /* Graphic with a zero height or width, typically copied from webpages, caused crashes. */
4236 if (!nXCroppedSize)
4237 nXCroppedSize = 100;
4238 if (!nYCroppedSize)
4239 nYCroppedSize = 100;
4241 //Given the original size and taking cropping into account
4242 //first, how much has the original been scaled to get the
4243 //final rendered size
4244 aRet.append(
4245 OOO_STRING_SVTOOLS_RTF_PICSCALEX
4246 + OString::number(static_cast<sal_Int32>((100 * rRendered.Width()) / nXCroppedSize))
4247 + OOO_STRING_SVTOOLS_RTF_PICSCALEY
4248 + OString::number(static_cast<sal_Int32>((100 * rRendered.Height()) / nYCroppedSize))
4250 + OOO_STRING_SVTOOLS_RTF_PICCROPL + OString::number(rCr.GetLeft())
4251 + OOO_STRING_SVTOOLS_RTF_PICCROPR + OString::number(rCr.GetRight())
4252 + OOO_STRING_SVTOOLS_RTF_PICCROPT + OString::number(rCr.GetTop())
4253 + OOO_STRING_SVTOOLS_RTF_PICCROPB + OString::number(rCr.GetBottom())
4255 + OOO_STRING_SVTOOLS_RTF_PICW + OString::number(static_cast<sal_Int32>(rMapped.Width()))
4256 + OOO_STRING_SVTOOLS_RTF_PICH
4257 + OString::number(static_cast<sal_Int32>(rMapped.Height()))
4259 + OOO_STRING_SVTOOLS_RTF_PICWGOAL
4260 + OString::number(static_cast<sal_Int32>(rOrig.Width()))
4261 + OOO_STRING_SVTOOLS_RTF_PICHGOAL
4262 + OString::number(static_cast<sal_Int32>(rOrig.Height()))
4264 + pBLIPType);
4265 if (bIsWMF)
4267 aRet.append(sal_Int32(8));
4268 msfilter::rtfutil::StripMetafileHeader(pGraphicAry, nSize);
4270 aRet.append(SAL_NEWLINE_STRING);
4271 if (pStream)
4273 pStream->WriteOString(aRet);
4274 aRet.setLength(0);
4276 if (pStream)
4277 msfilter::rtfutil::WriteHex(pGraphicAry, nSize, pStream);
4278 else
4279 aRet.append(msfilter::rtfutil::WriteHex(pGraphicAry, nSize));
4280 aRet.append('}');
4281 if (pStream)
4283 pStream->WriteOString(aRet);
4284 aRet.setLength(0);
4287 return aRet.makeStringAndClear();
4290 void RtfAttributeOutput::FlyFrameOLEReplacement(const SwFlyFrameFormat* pFlyFrameFormat,
4291 SwOLENode& rOLENode, const Size& rSize)
4293 m_aRunText->append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_SHPPICT);
4294 Size aSize(rOLENode.GetTwipSize());
4295 Size aRendered(aSize);
4296 aRendered.setWidth(rSize.Width());
4297 aRendered.setHeight(rSize.Height());
4298 const Graphic* pGraphic = rOLENode.GetGraphic();
4299 Size aMapped(pGraphic->GetPrefSize());
4300 auto& rCr = rOLENode.GetAttr(RES_GRFATR_CROPGRF);
4301 const char* pBLIPType = OOO_STRING_SVTOOLS_RTF_PNGBLIP;
4302 const sal_uInt8* pGraphicAry = nullptr;
4303 SvMemoryStream aStream;
4304 if (GraphicConverter::Export(aStream, *pGraphic, ConvertDataFormat::PNG) != ERRCODE_NONE)
4305 SAL_WARN("sw.rtf", "failed to export the graphic");
4306 sal_uInt32 nSize = aStream.TellEnd();
4307 pGraphicAry = static_cast<sal_uInt8 const*>(aStream.GetData());
4308 m_aRunText->append(ExportPICT(pFlyFrameFormat, aSize, aRendered, aMapped, rCr, pBLIPType,
4309 pGraphicAry, nSize, m_rExport));
4310 m_aRunText->append("}"); // shppict
4311 m_aRunText->append("{" OOO_STRING_SVTOOLS_RTF_NONSHPPICT);
4312 pBLIPType = OOO_STRING_SVTOOLS_RTF_WMETAFILE;
4313 SvMemoryStream aWmfStream;
4314 if (GraphicConverter::Export(aWmfStream, *pGraphic, ConvertDataFormat::WMF) != ERRCODE_NONE)
4315 SAL_WARN("sw.rtf", "failed to export the graphic");
4316 nSize = aWmfStream.TellEnd();
4317 pGraphicAry = static_cast<sal_uInt8 const*>(aWmfStream.GetData());
4318 m_aRunText->append(ExportPICT(pFlyFrameFormat, aSize, aRendered, aMapped, rCr, pBLIPType,
4319 pGraphicAry, nSize, m_rExport));
4320 m_aRunText->append("}"); // nonshppict
4323 bool RtfAttributeOutput::FlyFrameOLEMath(const SwFlyFrameFormat* pFlyFrameFormat,
4324 SwOLENode& rOLENode, const Size& rSize)
4326 uno::Reference<embed::XEmbeddedObject> xObj(rOLENode.GetOLEObj().GetOleRef());
4327 sal_Int64 nAspect = rOLENode.GetAspect();
4328 svt::EmbeddedObjectRef aObjRef(xObj, nAspect);
4329 SvGlobalName aObjName(aObjRef->getClassID());
4331 if (!SotExchange::IsMath(aObjName))
4332 return false;
4334 m_aRunText->append("{" LO_STRING_SVTOOLS_RTF_MMATH " ");
4335 uno::Reference<util::XCloseable> xClosable = xObj->getComponent();
4336 if (!xClosable.is())
4337 return false;
4338 auto pBase = dynamic_cast<oox::FormulaImExportBase*>(xClosable.get());
4339 SAL_WARN_IF(!pBase, "sw.rtf", "Math OLE object cannot write out RTF");
4340 if (pBase)
4342 OStringBuffer aBuf;
4343 pBase->writeFormulaRtf(aBuf, m_rExport.GetCurrentEncoding());
4344 m_aRunText->append(aBuf);
4347 // Replacement graphic.
4348 m_aRunText->append("{" LO_STRING_SVTOOLS_RTF_MMATHPICT " ");
4349 FlyFrameOLEReplacement(pFlyFrameFormat, rOLENode, rSize);
4350 m_aRunText->append("}"); // mmathPict
4351 m_aRunText->append("}"); // mmath
4353 return true;
4356 void RtfAttributeOutput::FlyFrameOLE(const SwFlyFrameFormat* pFlyFrameFormat, SwOLENode& rOLENode,
4357 const Size& rSize)
4359 if (FlyFrameOLEMath(pFlyFrameFormat, rOLENode, rSize))
4360 return;
4362 FlyFrameOLEReplacement(pFlyFrameFormat, rOLENode, rSize);
4365 void RtfAttributeOutput::FlyFrameGraphic(const SwFlyFrameFormat* pFlyFrameFormat,
4366 const SwGrfNode* pGrfNode)
4368 SvMemoryStream aStream;
4369 const sal_uInt8* pGraphicAry = nullptr;
4370 sal_uInt32 nSize = 0;
4372 const Graphic& rGraphic(pGrfNode->GetGrf());
4374 // If there is no graphic there is not much point in parsing it
4375 if (rGraphic.GetType() == GraphicType::NONE)
4376 return;
4378 ConvertDataFormat aConvertDestinationFormat = ConvertDataFormat::WMF;
4379 const char* pConvertDestinationBLIPType = OOO_STRING_SVTOOLS_RTF_WMETAFILE;
4381 GfxLink aGraphicLink;
4382 const char* pBLIPType = nullptr;
4383 if (rGraphic.IsGfxLink())
4385 aGraphicLink = rGraphic.GetGfxLink();
4386 nSize = aGraphicLink.GetDataSize();
4387 pGraphicAry = aGraphicLink.GetData();
4388 switch (aGraphicLink.GetType())
4390 // #i15508# trying to add BMP type for better exports, need to check if this works
4391 // checked, does not work. Also need to reset pGraphicAry to NULL to force conversion
4392 // to PNG, else the BMP array will be used.
4393 // It may work using direct DIB data, but that needs to be checked eventually
4395 // #i15508# before GfxLinkType::NativeBmp was added the graphic data
4396 // (to be hold in pGraphicAry) was not available; thus for now to stay
4397 // compatible, keep it that way by assigning NULL value to pGraphicAry
4398 case GfxLinkType::NativeBmp:
4399 // pBLIPType = OOO_STRING_SVTOOLS_RTF_WBITMAP;
4400 pGraphicAry = nullptr;
4401 break;
4403 case GfxLinkType::NativeJpg:
4404 pBLIPType = OOO_STRING_SVTOOLS_RTF_JPEGBLIP;
4405 break;
4406 case GfxLinkType::NativePng:
4407 pBLIPType = OOO_STRING_SVTOOLS_RTF_PNGBLIP;
4408 break;
4409 case GfxLinkType::NativeWmf:
4410 pBLIPType = aGraphicLink.IsEMF() ? OOO_STRING_SVTOOLS_RTF_EMFBLIP
4411 : OOO_STRING_SVTOOLS_RTF_WMETAFILE;
4412 break;
4413 case GfxLinkType::NativeGif:
4414 // GIF is not supported by RTF, but we override default conversion to WMF, PNG seems fits better here.
4415 aConvertDestinationFormat = ConvertDataFormat::PNG;
4416 pConvertDestinationBLIPType = OOO_STRING_SVTOOLS_RTF_PNGBLIP;
4417 break;
4418 default:
4419 break;
4423 GraphicType eGraphicType = rGraphic.GetType();
4424 if (!pGraphicAry)
4426 if (ERRCODE_NONE
4427 == GraphicConverter::Export(aStream, rGraphic,
4428 (eGraphicType == GraphicType::Bitmap)
4429 ? ConvertDataFormat::PNG
4430 : ConvertDataFormat::WMF))
4432 pBLIPType = (eGraphicType == GraphicType::Bitmap) ? OOO_STRING_SVTOOLS_RTF_PNGBLIP
4433 : OOO_STRING_SVTOOLS_RTF_WMETAFILE;
4434 nSize = aStream.TellEnd();
4435 pGraphicAry = static_cast<sal_uInt8 const*>(aStream.GetData());
4439 Size aMapped(eGraphicType == GraphicType::Bitmap ? rGraphic.GetSizePixel()
4440 : rGraphic.GetPrefSize());
4442 auto& rCr = pGrfNode->GetAttr(RES_GRFATR_CROPGRF);
4444 //Get original size in twips
4445 Size aSize(pGrfNode->GetTwipSize());
4446 Size aRendered(aSize);
4448 const SwFormatFrameSize& rS = pFlyFrameFormat->GetFrameSize();
4449 aRendered.setWidth(rS.GetWidth());
4450 aRendered.setHeight(rS.GetHeight());
4452 ww8::Frame* pFrame = nullptr;
4453 for (auto& rFrame : m_rExport.m_aFrames)
4455 if (pFlyFrameFormat == &rFrame.GetFrameFormat())
4457 pFrame = &rFrame;
4458 break;
4463 If the graphic is not of type WMF then we will have to store two
4464 graphics, one in the native format wrapped in shppict, and the other in
4465 the wmf format wrapped in nonshppict, so as to keep wordpad happy. If it's
4466 a wmf already then we don't need any such wrapping
4468 bool bIsWMF = pBLIPType && std::strcmp(pBLIPType, OOO_STRING_SVTOOLS_RTF_WMETAFILE) == 0;
4469 const SwAttrSet* pAttrSet = pGrfNode->GetpSwAttrSet();
4470 if (!pFrame || pFrame->IsInline())
4472 if (!bIsWMF)
4473 m_rExport.Strm().WriteOString(
4474 "{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_SHPPICT);
4476 else
4478 m_rExport.Strm().WriteOString(
4479 "{" OOO_STRING_SVTOOLS_RTF_SHP
4480 "{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_SHPINST);
4481 m_pFlyFrameSize = &aRendered;
4482 m_rExport.m_pParentFrame = pFrame;
4483 m_rExport.m_bOutFlyFrameAttrs = true;
4484 m_rExport.SetRTFFlySyntax(true);
4485 m_rExport.OutputFormat(pFrame->GetFrameFormat(), false, false, true);
4486 m_rExport.m_bOutFlyFrameAttrs = false;
4487 m_rExport.SetRTFFlySyntax(false);
4488 m_rExport.m_pParentFrame = nullptr;
4489 m_pFlyFrameSize = nullptr;
4490 std::vector<std::pair<OString, OString>> aFlyProperties{
4491 { "shapeType", OString::number(ESCHER_ShpInst_PictureFrame) },
4493 { "wzDescription", msfilter::rtfutil::OutString(pFlyFrameFormat->GetObjDescription(),
4494 m_rExport.GetCurrentEncoding()) },
4495 { "wzName", msfilter::rtfutil::OutString(pFlyFrameFormat->GetObjTitle(),
4496 m_rExport.GetCurrentEncoding()) }
4499 // If we have a wrap polygon, then handle that here.
4500 if (pFlyFrameFormat->GetSurround().IsContour())
4502 if (const SwNoTextNode* pNd
4503 = sw::util::GetNoTextNodeFromSwFrameFormat(*pFlyFrameFormat))
4505 const tools::PolyPolygon* pPolyPoly = pNd->HasContour();
4506 if (pPolyPoly && pPolyPoly->Count())
4508 tools::Polygon aPoly = sw::util::CorrectWordWrapPolygonForExport(
4509 *pPolyPoly, pNd, /*bCorrectCrop=*/true);
4510 OStringBuffer aVerticies;
4511 for (sal_uInt16 i = 0; i < aPoly.GetSize(); ++i)
4512 aVerticies.append(";(" + OString::number(aPoly[i].X()) + ","
4513 + OString::number(aPoly[i].Y()) + ")");
4514 aFlyProperties.push_back(std::make_pair<OString, OString>(
4515 "pWrapPolygonVertices",
4516 "8;" + OString::number(aPoly.GetSize()) + aVerticies));
4521 // Below text, behind document, opaque: they all refer to the same thing.
4522 if (!pFlyFrameFormat->GetOpaque().GetValue())
4523 aFlyProperties.push_back(std::make_pair<OString, OString>("fBehindDocument", "1"));
4525 if (pAttrSet)
4527 if (Degree10 nRot10 = pAttrSet->Get(RES_GRFATR_ROTATION).GetValue())
4529 // See writerfilter::rtftok::RTFSdrImport::applyProperty(),
4530 // positive rotation angles are clockwise in RTF, we have them
4531 // as counter-clockwise.
4532 // Additionally, RTF type is 0..360*2^16, our is 0..360*10.
4533 sal_Int32 nRot = nRot10.get() * -1 * RTF_MULTIPLIER / 10;
4534 aFlyProperties.emplace_back("rotation", OString::number(nRot));
4538 for (const std::pair<OString, OString>& rPair : aFlyProperties)
4540 m_rExport.Strm().WriteOString("{" OOO_STRING_SVTOOLS_RTF_SP "{");
4541 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_SN " ");
4542 m_rExport.Strm().WriteOString(rPair.first);
4543 m_rExport.Strm().WriteOString("}{" OOO_STRING_SVTOOLS_RTF_SV " ");
4544 m_rExport.Strm().WriteOString(rPair.second);
4545 m_rExport.Strm().WriteOString("}}");
4547 m_rExport.Strm().WriteOString("{" OOO_STRING_SVTOOLS_RTF_SP "{" OOO_STRING_SVTOOLS_RTF_SN
4548 " pib"
4549 "}{" OOO_STRING_SVTOOLS_RTF_SV " ");
4552 bool bWritePicProp = !pFrame || pFrame->IsInline();
4553 if (pBLIPType)
4554 ExportPICT(pFlyFrameFormat, aSize, aRendered, aMapped, rCr, pBLIPType, pGraphicAry, nSize,
4555 m_rExport, &m_rExport.Strm(), bWritePicProp, pAttrSet);
4556 else
4558 aStream.Seek(0);
4559 if (GraphicConverter::Export(aStream, rGraphic, aConvertDestinationFormat) != ERRCODE_NONE)
4560 SAL_WARN("sw.rtf", "failed to export the graphic");
4561 pBLIPType = pConvertDestinationBLIPType;
4562 nSize = aStream.TellEnd();
4563 pGraphicAry = static_cast<sal_uInt8 const*>(aStream.GetData());
4565 ExportPICT(pFlyFrameFormat, aSize, aRendered, aMapped, rCr, pBLIPType, pGraphicAry, nSize,
4566 m_rExport, &m_rExport.Strm(), bWritePicProp, pAttrSet);
4569 if (!pFrame || pFrame->IsInline())
4571 if (!bIsWMF)
4573 m_rExport.Strm().WriteOString("}"
4574 "{" OOO_STRING_SVTOOLS_RTF_NONSHPPICT);
4576 aStream.Seek(0);
4577 if (GraphicConverter::Export(aStream, rGraphic, ConvertDataFormat::WMF) != ERRCODE_NONE)
4578 SAL_WARN("sw.rtf", "failed to export the graphic");
4579 pBLIPType = OOO_STRING_SVTOOLS_RTF_WMETAFILE;
4580 nSize = aStream.TellEnd();
4581 pGraphicAry = static_cast<sal_uInt8 const*>(aStream.GetData());
4583 ExportPICT(pFlyFrameFormat, aSize, aRendered, aMapped, rCr, pBLIPType, pGraphicAry,
4584 nSize, m_rExport, &m_rExport.Strm());
4586 m_rExport.Strm().WriteChar('}');
4589 else
4590 m_rExport.Strm().WriteOString("}}}}"); // Close SV, SP, SHPINST and SHP.
4592 m_rExport.Strm().WriteOString(SAL_NEWLINE_STRING);
4595 void RtfAttributeOutput::BulletDefinition(int /*nId*/, const Graphic& rGraphic, Size aSize)
4597 m_rExport.Strm().WriteOString("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_SHPPICT);
4598 m_rExport.Strm().WriteOString("{" OOO_STRING_SVTOOLS_RTF_PICT OOO_STRING_SVTOOLS_RTF_PNGBLIP);
4600 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_PICWGOAL);
4601 m_rExport.Strm().WriteNumberAsString(aSize.Width());
4602 m_rExport.Strm().WriteOString(OOO_STRING_SVTOOLS_RTF_PICHGOAL);
4603 m_rExport.Strm().WriteNumberAsString(aSize.Height());
4605 m_rExport.Strm().WriteOString(SAL_NEWLINE_STRING);
4606 const sal_uInt8* pGraphicAry = nullptr;
4607 SvMemoryStream aStream;
4608 if (GraphicConverter::Export(aStream, rGraphic, ConvertDataFormat::PNG) != ERRCODE_NONE)
4609 SAL_WARN("sw.rtf", "failed to export the numbering picture bullet");
4610 sal_uInt32 nSize = aStream.TellEnd();
4611 pGraphicAry = static_cast<sal_uInt8 const*>(aStream.GetData());
4612 msfilter::rtfutil::WriteHex(pGraphicAry, nSize, &m_rExport.Strm());
4613 m_rExport.Strm().WriteOString("}}"); // pict, shppict
4616 void RtfAttributeOutput::SectionRtlGutter(const SfxBoolItem& rRtlGutter)
4618 if (!rRtlGutter.GetValue())
4620 return;
4623 m_rExport.Strm().WriteOString(LO_STRING_SVTOOLS_RTF_RTLGUTTER);
4626 void RtfAttributeOutput::TextLineBreak(const SwFormatLineBreak& rLineBreak)
4628 // Text wrapping break of type:
4629 m_aStyles.append(LO_STRING_SVTOOLS_RTF_LBR);
4630 m_aStyles.append(static_cast<sal_Int32>(rLineBreak.GetEnumValue()));
4632 // Write the linebreak itself.
4633 RunText("\x0b");
4636 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */