Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / writerfilter / source / rtftok / rtfdispatchvalue.cxx
blob4f7c71ecf73ee2df35e816f35dcd4df653bdbbde
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/.
8 */
10 #include "rtfdocumentimpl.hxx"
12 #include <com/sun/star/beans/XPropertySet.hpp>
13 #include <com/sun/star/text/WrapTextMode.hpp>
14 #include <com/sun/star/document/XDocumentProperties.hpp>
15 #include <comphelper/sequence.hxx>
16 #include <i18nlangtag/languagetag.hxx>
17 #include <osl/thread.h>
18 #include <sal/log.hxx>
19 #include <rtl/tencinfo.h>
20 #include <tools/mapunit.hxx>
22 #include <ooxml/resourceids.hxx>
24 #include "rtfcharsets.hxx"
25 #include "rtffly.hxx"
26 #include "rtfreferenceproperties.hxx"
27 #include "rtfskipdestination.hxx"
29 #include <officecfg/Setup.hxx>
30 #include <officecfg/Office/Linguistic.hxx>
31 #include <unotools/wincodepage.hxx>
33 using namespace com::sun::star;
35 namespace
37 OUString getLODefaultLanguage()
39 OUString result(::officecfg::Office::Linguistic::General::DefaultLocale::get());
40 if (result.isEmpty())
41 result = ::officecfg::Setup::L10N::ooSetupSystemLocale::get();
42 return result;
46 namespace writerfilter
48 static int getNumberFormat(int nParam)
50 static const int aMap[]
51 = { NS_ooxml::LN_Value_ST_NumberFormat_decimal,
52 NS_ooxml::LN_Value_ST_NumberFormat_upperRoman,
53 NS_ooxml::LN_Value_ST_NumberFormat_lowerRoman,
54 NS_ooxml::LN_Value_ST_NumberFormat_upperLetter,
55 NS_ooxml::LN_Value_ST_NumberFormat_lowerLetter,
56 NS_ooxml::LN_Value_ST_NumberFormat_ordinal,
57 NS_ooxml::LN_Value_ST_NumberFormat_cardinalText,
58 NS_ooxml::LN_Value_ST_NumberFormat_ordinalText,
59 NS_ooxml::LN_Value_ST_NumberFormat_none, // Undefined in RTF 1.8 spec.
60 NS_ooxml::LN_Value_ST_NumberFormat_none, // Undefined in RTF 1.8 spec.
61 NS_ooxml::LN_Value_ST_NumberFormat_ideographDigital,
62 NS_ooxml::LN_Value_ST_NumberFormat_japaneseCounting,
63 NS_ooxml::LN_Value_ST_NumberFormat_aiueo,
64 NS_ooxml::LN_Value_ST_NumberFormat_iroha,
65 NS_ooxml::LN_Value_ST_NumberFormat_decimalFullWidth,
66 NS_ooxml::LN_Value_ST_NumberFormat_decimalHalfWidth,
67 NS_ooxml::LN_Value_ST_NumberFormat_japaneseLegal,
68 NS_ooxml::LN_Value_ST_NumberFormat_japaneseDigitalTenThousand,
69 NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedCircleChinese,
70 NS_ooxml::LN_Value_ST_NumberFormat_decimalFullWidth2,
71 NS_ooxml::LN_Value_ST_NumberFormat_aiueoFullWidth,
72 NS_ooxml::LN_Value_ST_NumberFormat_irohaFullWidth,
73 NS_ooxml::LN_Value_ST_NumberFormat_decimalZero,
74 NS_ooxml::LN_Value_ST_NumberFormat_bullet,
75 NS_ooxml::LN_Value_ST_NumberFormat_ganada,
76 NS_ooxml::LN_Value_ST_NumberFormat_chosung,
77 NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedFullstop,
78 NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedParen,
79 NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedCircleChinese,
80 NS_ooxml::LN_Value_ST_NumberFormat_ideographEnclosedCircle,
81 NS_ooxml::LN_Value_ST_NumberFormat_ideographTraditional,
82 NS_ooxml::LN_Value_ST_NumberFormat_ideographZodiac,
83 NS_ooxml::LN_Value_ST_NumberFormat_ideographZodiacTraditional,
84 NS_ooxml::LN_Value_ST_NumberFormat_taiwaneseCounting,
85 NS_ooxml::LN_Value_ST_NumberFormat_ideographLegalTraditional,
86 NS_ooxml::LN_Value_ST_NumberFormat_taiwaneseCountingThousand,
87 NS_ooxml::LN_Value_ST_NumberFormat_taiwaneseDigital,
88 NS_ooxml::LN_Value_ST_NumberFormat_chineseCounting,
89 NS_ooxml::LN_Value_ST_NumberFormat_chineseLegalSimplified,
90 NS_ooxml::LN_Value_ST_NumberFormat_chineseCountingThousand,
91 NS_ooxml::LN_Value_ST_NumberFormat_decimal,
92 NS_ooxml::LN_Value_ST_NumberFormat_koreanDigital,
93 NS_ooxml::LN_Value_ST_NumberFormat_koreanCounting,
94 NS_ooxml::LN_Value_ST_NumberFormat_koreanLegal,
95 NS_ooxml::LN_Value_ST_NumberFormat_koreanDigital2,
96 NS_ooxml::LN_Value_ST_NumberFormat_hebrew1,
97 NS_ooxml::LN_Value_ST_NumberFormat_arabicAlpha,
98 NS_ooxml::LN_Value_ST_NumberFormat_hebrew2,
99 NS_ooxml::LN_Value_ST_NumberFormat_arabicAbjad };
100 const int nLen = SAL_N_ELEMENTS(aMap);
101 int nValue = 0;
102 if (nParam >= 0 && nParam < nLen)
103 nValue = aMap[nParam];
104 else // 255 and the other cases.
105 nValue = NS_ooxml::LN_Value_ST_NumberFormat_none;
106 return nValue;
109 namespace rtftok
111 RTFError RTFDocumentImpl::dispatchValue(RTFKeyword nKeyword, int nParam)
113 setNeedSect(true);
114 checkUnicode(/*bUnicode =*/nKeyword != RTF_U, /*bHex =*/true);
115 RTFSkipDestination aSkip(*this);
116 int nSprm = 0;
117 tools::SvRef<RTFValue> pIntValue(new RTFValue(nParam));
118 // Trivial table sprms.
119 switch (nKeyword)
121 case RTF_LEVELJC:
123 nSprm = NS_ooxml::LN_CT_Lvl_lvlJc;
124 int nValue = 0;
125 switch (nParam)
127 case 0:
128 nValue = NS_ooxml::LN_Value_ST_Jc_left;
129 break;
130 case 1:
131 nValue = NS_ooxml::LN_Value_ST_Jc_center;
132 break;
133 case 2:
134 nValue = NS_ooxml::LN_Value_ST_Jc_right;
135 break;
137 pIntValue = new RTFValue(nValue);
138 break;
140 case RTF_LEVELNFC:
141 nSprm = NS_ooxml::LN_CT_Lvl_numFmt;
142 pIntValue = new RTFValue(getNumberFormat(nParam));
143 break;
144 case RTF_LEVELSTARTAT:
145 nSprm = NS_ooxml::LN_CT_Lvl_start;
146 break;
147 case RTF_LEVELPICTURE:
148 nSprm = NS_ooxml::LN_CT_Lvl_lvlPicBulletId;
149 break;
150 case RTF_SBASEDON:
151 nSprm = NS_ooxml::LN_CT_Style_basedOn;
152 pIntValue = new RTFValue(getStyleName(nParam));
153 break;
154 default:
155 break;
157 if (nSprm > 0)
159 m_aStates.top().getTableSprms().set(nSprm, pIntValue);
160 return RTFError::OK;
162 // Trivial character sprms.
163 switch (nKeyword)
165 case RTF_FS:
166 case RTF_AFS:
167 switch (m_aStates.top().getRunType())
169 case RTFParserState::RunType::HICH:
170 case RTFParserState::RunType::RTLCH_LTRCH_1:
171 case RTFParserState::RunType::LTRCH_RTLCH_2:
172 case RTFParserState::RunType::DBCH:
173 nSprm = NS_ooxml::LN_EG_RPrBase_szCs;
174 break;
175 case RTFParserState::RunType::NONE:
176 case RTFParserState::RunType::LOCH:
177 case RTFParserState::RunType::LTRCH_RTLCH_1:
178 case RTFParserState::RunType::RTLCH_LTRCH_2:
179 default:
180 nSprm = NS_ooxml::LN_EG_RPrBase_sz;
181 break;
183 break;
184 case RTF_EXPNDTW:
185 nSprm = NS_ooxml::LN_EG_RPrBase_spacing;
186 break;
187 case RTF_KERNING:
188 nSprm = NS_ooxml::LN_EG_RPrBase_kern;
189 break;
190 case RTF_CHARSCALEX:
191 nSprm = NS_ooxml::LN_EG_RPrBase_w;
192 break;
193 default:
194 break;
196 if (nSprm > 0)
198 m_aStates.top().getCharacterSprms().set(nSprm, pIntValue);
199 return RTFError::OK;
201 // Trivial character attributes.
202 switch (nKeyword)
204 case RTF_LANG:
205 case RTF_ALANG:
206 switch (m_aStates.top().getRunType())
208 case RTFParserState::RunType::HICH:
209 case RTFParserState::RunType::RTLCH_LTRCH_1:
210 case RTFParserState::RunType::LTRCH_RTLCH_2:
211 nSprm = NS_ooxml::LN_CT_Language_bidi;
212 break;
213 case RTFParserState::RunType::DBCH:
214 nSprm = NS_ooxml::LN_CT_Language_eastAsia;
215 break;
216 case RTFParserState::RunType::NONE:
217 case RTFParserState::RunType::LOCH:
218 case RTFParserState::RunType::LTRCH_RTLCH_1:
219 case RTFParserState::RunType::RTLCH_LTRCH_2:
220 default:
221 nSprm = NS_ooxml::LN_CT_Language_val;
222 break;
224 break;
225 case RTF_LANGFE: // this one is always CJK apparently
226 nSprm = NS_ooxml::LN_CT_Language_eastAsia;
227 break;
228 default:
229 break;
231 if (nSprm > 0)
233 LanguageTag aTag((LanguageType(static_cast<sal_uInt16>(nParam))));
234 auto pValue = new RTFValue(aTag.getBcp47());
235 putNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_lang, nSprm,
236 pValue);
237 // Language is a character property, but we should store it at a paragraph level as well for fields.
238 if (nKeyword == RTF_LANG && m_bNeedPap)
239 putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_EG_RPrBase_lang,
240 nSprm, pValue);
241 return RTFError::OK;
243 // Trivial paragraph sprms.
244 switch (nKeyword)
246 case RTF_ITAP:
247 nSprm = NS_ooxml::LN_tblDepth;
248 // tdf#117268: If \itap0 is encountered inside tables (between \cellxN and \cell), then
249 // use the default value (1), as Word apparently does
250 if (nParam == 0 && (m_nTopLevelCells != 0 || m_nNestedCells != 0))
252 nParam = 1;
253 pIntValue = new RTFValue(nParam);
255 break;
256 default:
257 break;
259 if (nSprm > 0)
261 m_aStates.top().getParagraphSprms().set(nSprm, pIntValue);
262 if (nKeyword == RTF_ITAP && nParam > 0)
264 while (m_aTableBufferStack.size() < sal::static_int_cast<std::size_t>(nParam))
266 m_aTableBufferStack.emplace_back(RTFBuffer_t());
268 // Invalid tables may omit INTBL after ITAP
269 dispatchFlag(RTF_INTBL); // sets newly pushed buffer as current
270 assert(m_aStates.top().getCurrentBuffer() == &m_aTableBufferStack.back());
272 return RTFError::OK;
275 // Info group.
276 switch (nKeyword)
278 case RTF_YR:
280 m_aStates.top().setYear(nParam);
281 nSprm = 1;
283 break;
284 case RTF_MO:
286 m_aStates.top().setMonth(nParam);
287 nSprm = 1;
289 break;
290 case RTF_DY:
292 m_aStates.top().setDay(nParam);
293 nSprm = 1;
295 break;
296 case RTF_HR:
298 m_aStates.top().setHour(nParam);
299 nSprm = 1;
301 break;
302 case RTF_MIN:
304 m_aStates.top().setMinute(nParam);
305 nSprm = 1;
307 break;
308 default:
309 break;
311 if (nSprm > 0)
312 return RTFError::OK;
314 // Frame size / position.
315 Id nId = 0;
316 switch (nKeyword)
318 case RTF_ABSW:
319 nId = NS_ooxml::LN_CT_FramePr_w;
320 break;
321 case RTF_ABSH:
322 nId = NS_ooxml::LN_CT_FramePr_h;
323 break;
324 case RTF_POSX:
326 nId = NS_ooxml::LN_CT_FramePr_x;
327 m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_xAlign, 0);
329 break;
330 case RTF_POSY:
332 nId = NS_ooxml::LN_CT_FramePr_y;
333 m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign, 0);
335 break;
336 default:
337 break;
340 if (nId > 0)
342 m_bNeedPap = true;
343 // Don't try to support text frames inside tables for now.
344 if (m_aStates.top().getCurrentBuffer() != &m_aTableBufferStack.back())
345 m_aStates.top().getFrame().setSprm(nId, nParam);
347 return RTFError::OK;
350 // Then check for the more complex ones.
351 switch (nKeyword)
353 case RTF_F:
354 case RTF_AF:
355 switch (m_aStates.top().getRunType())
357 case RTFParserState::RunType::HICH:
358 case RTFParserState::RunType::RTLCH_LTRCH_1:
359 case RTFParserState::RunType::LTRCH_RTLCH_2:
360 nSprm = NS_ooxml::LN_CT_Fonts_cs;
361 break;
362 case RTFParserState::RunType::DBCH:
363 nSprm = NS_ooxml::LN_CT_Fonts_eastAsia;
364 break;
365 case RTFParserState::RunType::NONE:
366 case RTFParserState::RunType::LOCH:
367 case RTFParserState::RunType::LTRCH_RTLCH_1:
368 case RTFParserState::RunType::RTLCH_LTRCH_2:
369 default:
370 nSprm = NS_ooxml::LN_CT_Fonts_ascii;
371 break;
374 if (m_aStates.top().getDestination() == Destination::FONTTABLE
375 || m_aStates.top().getDestination() == Destination::FONTENTRY)
377 m_aFontIndexes.push_back(nParam);
378 m_nCurrentFontIndex = getFontIndex(nParam);
380 else if (m_aStates.top().getDestination() == Destination::LISTLEVEL)
382 RTFSprms aFontAttributes;
383 aFontAttributes.set(nSprm, new RTFValue(m_aFontNames[getFontIndex(nParam)]));
384 RTFSprms aRunPropsSprms;
385 aRunPropsSprms.set(NS_ooxml::LN_EG_RPrBase_rFonts, new RTFValue(aFontAttributes));
386 m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Lvl_rPr,
387 new RTFValue(RTFSprms(), aRunPropsSprms),
388 RTFOverwrite::NO_APPEND);
390 else
392 m_nCurrentFontIndex = getFontIndex(nParam);
393 auto pValue = new RTFValue(getFontName(m_nCurrentFontIndex));
394 putNestedAttribute(m_aStates.top().getCharacterSprms(),
395 NS_ooxml::LN_EG_RPrBase_rFonts, nSprm, pValue);
396 if (nKeyword == RTF_F)
397 m_aStates.top().setCurrentEncoding(getEncoding(m_nCurrentFontIndex));
399 break;
400 case RTF_RED:
401 m_aStates.top().getCurrentColor().SetRed(nParam);
402 break;
403 case RTF_GREEN:
404 m_aStates.top().getCurrentColor().SetGreen(nParam);
405 break;
406 case RTF_BLUE:
407 m_aStates.top().getCurrentColor().SetBlue(nParam);
408 break;
409 case RTF_FCHARSET:
411 // we always send text to the domain mapper in OUString, so no
412 // need to send encoding info
413 int i;
414 for (i = 0; i < nRTFEncodings; i++)
416 if (aRTFEncodings[i].charset == nParam)
417 break;
419 if (i == nRTFEncodings)
420 // not found
421 return RTFError::OK;
423 m_nCurrentEncoding
424 = aRTFEncodings[i].codepage == 0 // Default (CP_ACP)
425 ? osl_getThreadTextEncoding()
426 : rtl_getTextEncodingFromWindowsCodePage(aRTFEncodings[i].codepage);
427 m_aStates.top().setCurrentEncoding(m_nCurrentEncoding);
429 break;
430 case RTF_ANSICPG:
431 case RTF_CPG:
433 rtl_TextEncoding nEncoding
434 = (nParam == 0)
435 ? utl_getWinTextEncodingFromLangStr(getLODefaultLanguage().toUtf8().getStr())
436 : rtl_getTextEncodingFromWindowsCodePage(nParam);
437 if (nKeyword == RTF_ANSICPG)
438 m_aDefaultState.setCurrentEncoding(nEncoding);
439 else
440 m_nCurrentEncoding = nEncoding;
441 m_aStates.top().setCurrentEncoding(nEncoding);
443 break;
444 case RTF_CF:
446 RTFSprms aAttributes;
447 auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam)));
448 aAttributes.set(NS_ooxml::LN_CT_Color_val, pValue);
449 m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_color,
450 new RTFValue(aAttributes));
452 break;
453 case RTF_S:
455 m_aStates.top().setCurrentStyleIndex(nParam);
457 if (m_aStates.top().getDestination() == Destination::STYLESHEET
458 || m_aStates.top().getDestination() == Destination::STYLEENTRY)
460 m_nCurrentStyleIndex = nParam;
461 auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_StyleType_paragraph);
462 m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_type,
463 pValue); // paragraph style
465 else
467 OUString aName = getStyleName(nParam);
468 if (!aName.isEmpty())
470 if (m_aStates.top().getDestination() == Destination::LISTLEVEL)
471 m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Lvl_pStyle,
472 new RTFValue(aName));
473 else
474 m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_pStyle,
475 new RTFValue(aName));
479 break;
480 case RTF_CS:
481 m_aStates.top().setCurrentCharacterStyleIndex(nParam);
482 if (m_aStates.top().getDestination() == Destination::STYLESHEET
483 || m_aStates.top().getDestination() == Destination::STYLEENTRY)
485 m_nCurrentStyleIndex = nParam;
486 auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_StyleType_character);
487 m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_type,
488 pValue); // character style
490 else
492 OUString aName = getStyleName(nParam);
493 if (!aName.isEmpty())
494 m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_rStyle,
495 new RTFValue(aName));
497 break;
498 case RTF_DS:
499 if (m_aStates.top().getDestination() == Destination::STYLESHEET
500 || m_aStates.top().getDestination() == Destination::STYLEENTRY)
502 m_nCurrentStyleIndex = nParam;
503 auto pValue = new RTFValue(0); // TODO no value in enum StyleType?
504 m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_type,
505 pValue); // section style
507 break;
508 case RTF_TS:
509 if (m_aStates.top().getDestination() == Destination::STYLESHEET
510 || m_aStates.top().getDestination() == Destination::STYLEENTRY)
512 m_nCurrentStyleIndex = nParam;
513 // FIXME the correct value would be NS_ooxml::LN_Value_ST_StyleType_table but maybe table styles mess things up in dmapper, be cautious and disable them for now
514 auto pValue = new RTFValue(0);
515 m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_type,
516 pValue); // table style
518 break;
519 case RTF_DEFF:
520 m_nDefaultFontIndex = nParam;
521 break;
522 case RTF_STSHFDBCH:
523 // tdf#123703 switch off longer space sequence except in the case of the fixed compatibility setting font id 31505
524 if (nParam != 31505)
525 m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_longerSpaceSequence,
526 new RTFValue(0));
527 break;
528 case RTF_DEFLANG:
529 case RTF_ADEFLANG:
531 LanguageTag aTag((LanguageType(static_cast<sal_uInt16>(nParam))));
532 auto pValue = new RTFValue(aTag.getBcp47());
533 putNestedAttribute(m_aStates.top().getCharacterSprms(),
534 (nKeyword == RTF_DEFLANG ? NS_ooxml::LN_EG_RPrBase_lang
535 : NS_ooxml::LN_CT_Language_bidi),
536 nSprm, pValue);
538 break;
539 case RTF_CHCBPAT:
541 auto pValue = new RTFValue(sal_uInt32(nParam ? getColorTable(nParam) : COL_AUTO));
542 putNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_shd,
543 NS_ooxml::LN_CT_Shd_fill, pValue);
545 break;
546 case RTF_CLCBPAT:
547 case RTF_CLCBPATRAW:
549 auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam)));
550 putNestedAttribute(m_aStates.top().getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_shd,
551 NS_ooxml::LN_CT_Shd_fill, pValue);
553 break;
554 case RTF_CBPAT:
555 if (nParam)
557 auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam)));
558 putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PrBase_shd,
559 NS_ooxml::LN_CT_Shd_fill, pValue);
561 break;
562 case RTF_ULC:
564 auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam)));
565 m_aStates.top().getCharacterSprms().set(0x6877, pValue);
567 break;
568 case RTF_HIGHLIGHT:
570 auto pValue = new RTFValue(sal_uInt32(nParam ? getColorTable(nParam) : COL_AUTO));
571 m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_highlight, pValue);
573 break;
574 case RTF_UP:
575 case RTF_DN:
577 auto pValue = new RTFValue(nParam * (nKeyword == RTF_UP ? 1 : -1));
578 m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_position, pValue);
580 break;
581 case RTF_HORZVERT:
583 auto pValue = new RTFValue(int(true));
584 m_aStates.top().getCharacterAttributes().set(NS_ooxml::LN_CT_EastAsianLayout_vert,
585 pValue);
586 if (nParam)
587 // rotate fits to a single line
588 m_aStates.top().getCharacterAttributes().set(
589 NS_ooxml::LN_CT_EastAsianLayout_vertCompress, pValue);
591 break;
592 case RTF_EXPND:
594 // Convert quarter-points to twentieths of a point
595 auto pValue = new RTFValue(nParam * 5);
596 m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_spacing, pValue);
598 break;
599 case RTF_TWOINONE:
601 auto pValue = new RTFValue(int(true));
602 m_aStates.top().getCharacterAttributes().set(NS_ooxml::LN_CT_EastAsianLayout_combine,
603 pValue);
604 nId = 0;
605 switch (nParam)
607 case 0:
608 nId = NS_ooxml::LN_Value_ST_CombineBrackets_none;
609 break;
610 case 1:
611 nId = NS_ooxml::LN_Value_ST_CombineBrackets_round;
612 break;
613 case 2:
614 nId = NS_ooxml::LN_Value_ST_CombineBrackets_square;
615 break;
616 case 3:
617 nId = NS_ooxml::LN_Value_ST_CombineBrackets_angle;
618 break;
619 case 4:
620 nId = NS_ooxml::LN_Value_ST_CombineBrackets_curly;
621 break;
623 if (nId > 0)
624 m_aStates.top().getCharacterAttributes().set(
625 NS_ooxml::LN_CT_EastAsianLayout_combineBrackets, new RTFValue(nId));
627 break;
628 case RTF_SL:
630 // This is similar to RTF_ABSH, negative value means 'exact', positive means 'at least'.
631 tools::SvRef<RTFValue> pValue(
632 new RTFValue(NS_ooxml::LN_Value_doc_ST_LineSpacingRule_atLeast));
633 if (nParam < 0)
635 pValue = new RTFValue(NS_ooxml::LN_Value_doc_ST_LineSpacingRule_exact);
636 pIntValue = new RTFValue(-nParam);
638 m_aStates.top().getParagraphAttributes().set(NS_ooxml::LN_CT_Spacing_lineRule, pValue);
639 m_aStates.top().getParagraphAttributes().set(NS_ooxml::LN_CT_Spacing_line, pIntValue);
641 break;
642 case RTF_SLMULT:
643 if (nParam > 0)
645 auto pValue = new RTFValue(NS_ooxml::LN_Value_doc_ST_LineSpacingRule_auto);
646 m_aStates.top().getParagraphAttributes().set(NS_ooxml::LN_CT_Spacing_lineRule,
647 pValue);
649 break;
650 case RTF_BRDRW:
652 // dmapper expects it in 1/8 pt, we have it in twip - but avoid rounding 1 to 0
653 if (nParam > 1)
654 nParam = nParam * 2 / 5;
655 auto pValue = new RTFValue(nParam);
656 putBorderProperty(m_aStates, NS_ooxml::LN_CT_Border_sz, pValue);
658 break;
659 case RTF_BRDRCF:
661 auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam)));
662 putBorderProperty(m_aStates, NS_ooxml::LN_CT_Border_color, pValue);
664 break;
665 case RTF_BRSP:
667 // dmapper expects it in points, we have it in twip
668 auto pValue = new RTFValue(nParam / 20);
669 putBorderProperty(m_aStates, NS_ooxml::LN_CT_Border_space, pValue);
671 break;
672 case RTF_TX:
674 m_aStates.top().getTabAttributes().set(NS_ooxml::LN_CT_TabStop_pos, pIntValue);
675 auto pValue = new RTFValue(m_aStates.top().getTabAttributes());
676 if (m_aStates.top().getDestination() == Destination::LISTLEVEL)
677 putNestedSprm(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_PPrBase_tabs,
678 NS_ooxml::LN_CT_Tabs_tab, pValue);
679 else
680 putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_tabs,
681 NS_ooxml::LN_CT_Tabs_tab, pValue);
682 m_aStates.top().getTabAttributes().clear();
684 break;
685 case RTF_ILVL:
686 putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_numPr,
687 NS_ooxml::LN_CT_NumPr_ilvl, pIntValue);
688 break;
689 case RTF_LISTTEMPLATEID:
690 // This one is not referenced anywhere, so it's pointless to store it at the moment.
691 break;
692 case RTF_LISTID:
694 if (m_aStates.top().getDestination() == Destination::LISTENTRY)
695 m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_AbstractNum_abstractNumId,
696 pIntValue);
697 else if (m_aStates.top().getDestination() == Destination::LISTOVERRIDEENTRY)
698 m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Num_abstractNumId, pIntValue);
699 m_aStates.top().setCurrentListIndex(nParam);
701 break;
702 case RTF_LS:
704 if (m_aStates.top().getDestination() == Destination::LISTOVERRIDEENTRY)
706 m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_AbstractNum_nsid,
707 pIntValue);
708 m_aStates.top().setCurrentListOverrideIndex(nParam);
710 else
712 // Insert at the start, so properties inherited from the list
713 // can be overridden by direct formatting. But still allow the
714 // case when old-style paragraph numbering is already
715 // tokenized.
716 putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_numPr,
717 NS_ooxml::LN_CT_NumPr_numId, pIntValue, RTFOverwrite::YES_PREPEND);
720 break;
721 case RTF_UC:
722 if ((SAL_MIN_INT16 <= nParam) && (nParam <= SAL_MAX_INT16))
723 m_aStates.top().setUc(nParam);
724 break;
725 case RTF_U:
726 // sal_Unicode is unsigned 16-bit, RTF may represent that as a
727 // signed SAL_MIN_INT16..SAL_MAX_INT16 or 0..SAL_MAX_UINT16. The
728 // static_cast() will do the right thing.
729 if ((SAL_MIN_INT16 <= nParam) && (nParam <= SAL_MAX_UINT16))
731 if (m_aStates.top().getDestination() == Destination::LEVELNUMBERS)
733 if (nParam != ';')
734 m_aStates.top().getLevelNumbers().push_back(sal_Int32(nParam));
735 else
736 // ';' in \u form is not considered valid.
737 m_aStates.top().setLevelNumbersValid(false);
739 else
740 m_aUnicodeBuffer.append(static_cast<sal_Unicode>(nParam));
741 m_aStates.top().getCharsToSkip() = m_aStates.top().getUc();
743 break;
744 case RTF_LEVELFOLLOW:
746 OUString sValue;
747 switch (nParam)
749 case 0:
750 sValue = "tab";
751 break;
752 case 1:
753 sValue = "space";
754 break;
755 case 2:
756 sValue = "nothing";
757 break;
759 if (!sValue.isEmpty())
760 m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Lvl_suff, new RTFValue(sValue));
762 break;
763 case RTF_FPRQ:
765 sal_Int32 nValue = 0;
766 switch (nParam)
768 case 0:
769 nValue = NS_ooxml::LN_Value_ST_Pitch_default;
770 break;
771 case 1:
772 nValue = NS_ooxml::LN_Value_ST_Pitch_fixed;
773 break;
774 case 2:
775 nValue = NS_ooxml::LN_Value_ST_Pitch_variable;
776 break;
778 if (nValue)
780 RTFSprms aAttributes;
781 aAttributes.set(NS_ooxml::LN_CT_Pitch_val, new RTFValue(nValue));
782 m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Font_pitch,
783 new RTFValue(aAttributes));
786 break;
787 case RTF_LISTOVERRIDECOUNT:
788 // Ignore this for now, the exporter always emits it with a zero parameter.
789 break;
790 case RTF_PICSCALEX:
791 m_aStates.top().getPicture().nScaleX = nParam;
792 break;
793 case RTF_PICSCALEY:
794 m_aStates.top().getPicture().nScaleY = nParam;
795 break;
796 case RTF_PICW:
797 m_aStates.top().getPicture().nWidth = nParam;
798 break;
799 case RTF_PICH:
800 m_aStates.top().getPicture().nHeight = nParam;
801 break;
802 case RTF_PICWGOAL:
803 m_aStates.top().getPicture().nGoalWidth = convertTwipToMm100(nParam);
804 break;
805 case RTF_PICHGOAL:
806 m_aStates.top().getPicture().nGoalHeight = convertTwipToMm100(nParam);
807 break;
808 case RTF_PICCROPL:
809 m_aStates.top().getPicture().nCropL = convertTwipToMm100(nParam);
810 break;
811 case RTF_PICCROPR:
812 m_aStates.top().getPicture().nCropR = convertTwipToMm100(nParam);
813 break;
814 case RTF_PICCROPT:
815 m_aStates.top().getPicture().nCropT = convertTwipToMm100(nParam);
816 break;
817 case RTF_PICCROPB:
818 m_aStates.top().getPicture().nCropB = convertTwipToMm100(nParam);
819 break;
820 case RTF_SHPWRK:
822 int nValue = 0;
823 switch (nParam)
825 case 0:
826 nValue = NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_bothSides;
827 break;
828 case 1:
829 nValue = NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_left;
830 break;
831 case 2:
832 nValue = NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_right;
833 break;
834 case 3:
835 nValue = NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_largest;
836 break;
837 default:
838 break;
840 auto pValue = new RTFValue(nValue);
841 RTFValue::Pointer_t pTight
842 = m_aStates.top().getCharacterSprms().find(NS_ooxml::LN_EG_WrapType_wrapTight);
843 if (pTight)
844 pTight->getAttributes().set(NS_ooxml::LN_CT_WrapTight_wrapText, pValue);
845 else
846 m_aStates.top().getCharacterAttributes().set(NS_ooxml::LN_CT_WrapSquare_wrapText,
847 pValue);
849 break;
850 case RTF_SHPWR:
852 switch (nParam)
854 case 1:
855 m_aStates.top().getShape().setWrap(text::WrapTextMode_NONE);
856 break;
857 case 2:
858 m_aStates.top().getShape().setWrap(text::WrapTextMode_PARALLEL);
859 break;
860 case 3:
861 m_aStates.top().getShape().setWrap(text::WrapTextMode_THROUGH);
862 m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_WrapType_wrapNone,
863 new RTFValue());
864 break;
865 case 4:
866 m_aStates.top().getShape().setWrap(text::WrapTextMode_PARALLEL);
867 m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_WrapType_wrapTight,
868 new RTFValue());
869 break;
870 case 5:
871 m_aStates.top().getShape().setWrap(text::WrapTextMode_THROUGH);
872 break;
875 break;
876 case RTF_CELLX:
878 int& rCurrentCellX(
879 (Destination::NESTEDTABLEPROPERTIES == m_aStates.top().getDestination())
880 ? m_nNestedCurrentCellX
881 : m_nTopLevelCurrentCellX);
882 int nCellX = nParam - rCurrentCellX;
883 const int COL_DFLT_WIDTH
884 = 41; // sw/source/filter/inc/wrtswtbl.hxx, minimal possible width of cells.
885 if (!nCellX)
886 nCellX = COL_DFLT_WIDTH;
888 // If there is a negative left margin, then the first cellx is relative to that.
889 RTFValue::Pointer_t pTblInd
890 = m_aStates.top().getTableRowSprms().find(NS_ooxml::LN_CT_TblPrBase_tblInd);
891 if (rCurrentCellX == 0 && pTblInd.get())
893 RTFValue::Pointer_t pWidth
894 = pTblInd->getAttributes().find(NS_ooxml::LN_CT_TblWidth_w);
895 if (pWidth.get() && pWidth->getInt() < 0)
896 nCellX = -1 * (pWidth->getInt() - nParam);
899 rCurrentCellX = nParam;
900 auto pXValue = new RTFValue(nCellX);
901 m_aStates.top().getTableRowSprms().set(NS_ooxml::LN_CT_TblGridBase_gridCol, pXValue,
902 RTFOverwrite::NO_APPEND);
903 if (Destination::NESTEDTABLEPROPERTIES == m_aStates.top().getDestination())
905 m_nNestedCells++;
906 // Push cell properties.
907 m_aNestedTableCellsSprms.push_back(m_aStates.top().getTableCellSprms());
908 m_aNestedTableCellsAttributes.push_back(m_aStates.top().getTableCellAttributes());
910 else
912 m_nTopLevelCells++;
913 // Push cell properties.
914 m_aTopLevelTableCellsSprms.push_back(m_aStates.top().getTableCellSprms());
915 m_aTopLevelTableCellsAttributes.push_back(m_aStates.top().getTableCellAttributes());
918 m_aStates.top().getTableCellSprms() = m_aDefaultState.getTableCellSprms();
919 m_aStates.top().getTableCellAttributes() = m_aDefaultState.getTableCellAttributes();
920 // We assume text after a row definition always belongs to the table, to handle text before the real INTBL token
921 dispatchFlag(RTF_INTBL);
922 if (!m_nCellxMax)
924 // Wasn't in table, but now is -> tblStart.
925 RTFSprms aAttributes;
926 RTFSprms aSprms;
927 aSprms.set(NS_ooxml::LN_tblStart, new RTFValue(1));
928 writerfilter::Reference<Properties>::Pointer_t pProperties
929 = new RTFReferenceProperties(aAttributes, aSprms);
930 Mapper().props(pProperties);
932 m_nCellxMax = std::max(m_nCellxMax, nParam);
934 break;
935 case RTF_TRRH:
937 OUString hRule("auto");
938 if (nParam < 0)
940 tools::SvRef<RTFValue> pAbsValue(new RTFValue(-nParam));
941 std::swap(pIntValue, pAbsValue);
943 hRule = "exact";
945 else if (nParam > 0)
946 hRule = "atLeast";
948 putNestedAttribute(m_aStates.top().getTableRowSprms(),
949 NS_ooxml::LN_CT_TrPrBase_trHeight, NS_ooxml::LN_CT_Height_val,
950 pIntValue);
952 auto pHRule = new RTFValue(hRule);
953 putNestedAttribute(m_aStates.top().getTableRowSprms(),
954 NS_ooxml::LN_CT_TrPrBase_trHeight, NS_ooxml::LN_CT_Height_hRule,
955 pHRule);
957 break;
958 case RTF_TRLEFT:
960 // the value is in twips
961 putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblInd,
962 NS_ooxml::LN_CT_TblWidth_type,
963 new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa));
964 putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblInd,
965 NS_ooxml::LN_CT_TblWidth_w, new RTFValue(nParam));
966 auto const aDestination = m_aStates.top().getDestination();
967 int& rCurrentTRLeft((Destination::NESTEDTABLEPROPERTIES == aDestination)
968 ? m_nNestedTRLeft
969 : m_nTopLevelTRLeft);
970 int& rCurrentCellX((Destination::NESTEDTABLEPROPERTIES == aDestination)
971 ? m_nNestedCurrentCellX
972 : m_nTopLevelCurrentCellX);
973 rCurrentTRLeft = rCurrentCellX = nParam;
975 break;
976 case RTF_COLS:
977 putNestedAttribute(m_aStates.top().getSectionSprms(),
978 NS_ooxml::LN_EG_SectPrContents_cols, NS_ooxml::LN_CT_Columns_num,
979 pIntValue);
980 break;
981 case RTF_COLSX:
982 putNestedAttribute(m_aStates.top().getSectionSprms(),
983 NS_ooxml::LN_EG_SectPrContents_cols, NS_ooxml::LN_CT_Columns_space,
984 pIntValue);
985 break;
986 case RTF_COLNO:
987 putNestedSprm(m_aStates.top().getSectionSprms(), NS_ooxml::LN_EG_SectPrContents_cols,
988 NS_ooxml::LN_CT_Columns_col, pIntValue);
989 break;
990 case RTF_COLW:
991 case RTF_COLSR:
993 RTFSprms& rAttributes = getLastAttributes(m_aStates.top().getSectionSprms(),
994 NS_ooxml::LN_EG_SectPrContents_cols);
995 rAttributes.set(
996 (nKeyword == RTF_COLW ? NS_ooxml::LN_CT_Column_w : NS_ooxml::LN_CT_Column_space),
997 pIntValue);
999 break;
1000 case RTF_PAPERH:
1001 putNestedAttribute(m_aDefaultState.getSectionSprms(),
1002 NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_h,
1003 pIntValue);
1004 [[fallthrough]]; // set the default + current value
1005 case RTF_PGHSXN:
1006 putNestedAttribute(m_aStates.top().getSectionSprms(),
1007 NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_h,
1008 pIntValue);
1009 break;
1010 case RTF_PAPERW:
1011 putNestedAttribute(m_aDefaultState.getSectionSprms(),
1012 NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_w,
1013 pIntValue);
1014 [[fallthrough]]; // set the default + current value
1015 case RTF_PGWSXN:
1016 putNestedAttribute(m_aStates.top().getSectionSprms(),
1017 NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_w,
1018 pIntValue);
1019 break;
1020 case RTF_MARGL:
1021 putNestedAttribute(m_aDefaultState.getSectionSprms(),
1022 NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_left,
1023 pIntValue);
1024 [[fallthrough]]; // set the default + current value
1025 case RTF_MARGLSXN:
1026 putNestedAttribute(m_aStates.top().getSectionSprms(),
1027 NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_left,
1028 pIntValue);
1029 break;
1030 case RTF_MARGR:
1031 putNestedAttribute(m_aDefaultState.getSectionSprms(),
1032 NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_right,
1033 pIntValue);
1034 [[fallthrough]]; // set the default + current value
1035 case RTF_MARGRSXN:
1036 putNestedAttribute(m_aStates.top().getSectionSprms(),
1037 NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_right,
1038 pIntValue);
1039 break;
1040 case RTF_MARGT:
1041 putNestedAttribute(m_aDefaultState.getSectionSprms(),
1042 NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_top,
1043 pIntValue);
1044 [[fallthrough]]; // set the default + current value
1045 case RTF_MARGTSXN:
1046 putNestedAttribute(m_aStates.top().getSectionSprms(),
1047 NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_top,
1048 pIntValue);
1049 break;
1050 case RTF_MARGB:
1051 putNestedAttribute(m_aDefaultState.getSectionSprms(),
1052 NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_bottom,
1053 pIntValue);
1054 [[fallthrough]]; // set the default + current value
1055 case RTF_MARGBSXN:
1056 putNestedAttribute(m_aStates.top().getSectionSprms(),
1057 NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_bottom,
1058 pIntValue);
1059 break;
1060 case RTF_HEADERY:
1061 putNestedAttribute(m_aStates.top().getSectionSprms(),
1062 NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_header,
1063 pIntValue);
1064 break;
1065 case RTF_FOOTERY:
1066 putNestedAttribute(m_aStates.top().getSectionSprms(),
1067 NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_footer,
1068 pIntValue);
1069 break;
1070 case RTF_DEFTAB:
1071 m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_defaultTabStop, pIntValue);
1072 break;
1073 case RTF_LINEMOD:
1074 putNestedAttribute(m_aStates.top().getSectionSprms(),
1075 NS_ooxml::LN_EG_SectPrContents_lnNumType,
1076 NS_ooxml::LN_CT_LineNumber_countBy, pIntValue);
1077 break;
1078 case RTF_LINEX:
1079 if (nParam)
1080 putNestedAttribute(m_aStates.top().getSectionSprms(),
1081 NS_ooxml::LN_EG_SectPrContents_lnNumType,
1082 NS_ooxml::LN_CT_LineNumber_distance, pIntValue);
1083 break;
1084 case RTF_LINESTARTS:
1086 // OOXML <w:lnNumType w:start="..."/> is 0-based, RTF is 1-based.
1087 auto pStart = tools::make_ref<RTFValue>(nParam - 1);
1088 putNestedAttribute(m_aStates.top().getSectionSprms(),
1089 NS_ooxml::LN_EG_SectPrContents_lnNumType,
1090 NS_ooxml::LN_CT_LineNumber_start, pStart);
1092 break;
1093 case RTF_REVAUTH:
1094 case RTF_REVAUTHDEL:
1096 auto pValue = new RTFValue(m_aAuthors[nParam]);
1097 putNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_trackchange,
1098 NS_ooxml::LN_CT_TrackChange_author, pValue);
1100 break;
1101 case RTF_REVDTTM:
1102 case RTF_REVDTTMDEL:
1104 OUString aStr(
1105 OStringToOUString(DTTM22OString(nParam), m_aStates.top().getCurrentEncoding()));
1106 auto pValue = new RTFValue(aStr);
1107 putNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_trackchange,
1108 NS_ooxml::LN_CT_TrackChange_date, pValue);
1110 break;
1111 case RTF_SHPLEFT:
1112 m_aStates.top().getShape().setLeft(convertTwipToMm100(nParam));
1113 break;
1114 case RTF_SHPTOP:
1115 m_aStates.top().getShape().setTop(convertTwipToMm100(nParam));
1116 break;
1117 case RTF_SHPRIGHT:
1118 m_aStates.top().getShape().setRight(convertTwipToMm100(nParam));
1119 break;
1120 case RTF_SHPBOTTOM:
1121 m_aStates.top().getShape().setBottom(convertTwipToMm100(nParam));
1122 break;
1123 case RTF_SHPZ:
1124 m_aStates.top().getShape().setZ(nParam);
1125 break;
1126 case RTF_FFTYPE:
1127 switch (nParam)
1129 case 0:
1130 m_nFormFieldType = RTFFormFieldType::TEXT;
1131 break;
1132 case 1:
1133 m_nFormFieldType = RTFFormFieldType::CHECKBOX;
1134 break;
1135 case 2:
1136 m_nFormFieldType = RTFFormFieldType::LIST;
1137 break;
1138 default:
1139 m_nFormFieldType = RTFFormFieldType::NONE;
1140 break;
1142 break;
1143 case RTF_FFDEFRES:
1144 if (m_nFormFieldType == RTFFormFieldType::CHECKBOX)
1145 m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFCheckBox_default, pIntValue);
1146 else if (m_nFormFieldType == RTFFormFieldType::LIST)
1147 m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFDDList_default, pIntValue);
1148 break;
1149 case RTF_FFRES:
1150 // 25 means undefined, see [MS-DOC] 2.9.79, FFDataBits.
1151 if (m_nFormFieldType == RTFFormFieldType::CHECKBOX && nParam != 25)
1152 m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFCheckBox_checked, pIntValue);
1153 else if (m_nFormFieldType == RTFFormFieldType::LIST)
1154 m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFDDList_result, pIntValue);
1155 break;
1156 case RTF_EDMINS:
1157 if (m_xDocumentProperties.is())
1159 // tdf#116851 some RTF may be malformed
1160 if (nParam < 0)
1161 nParam = -nParam;
1162 m_xDocumentProperties->setEditingDuration(nParam);
1164 break;
1165 case RTF_NOFPAGES:
1166 case RTF_NOFWORDS:
1167 case RTF_NOFCHARS:
1168 case RTF_NOFCHARSWS:
1169 if (m_xDocumentProperties.is())
1171 comphelper::SequenceAsHashMap aSeq = m_xDocumentProperties->getDocumentStatistics();
1172 OUString aName;
1173 switch (nKeyword)
1175 case RTF_NOFPAGES:
1176 aName = "PageCount";
1177 nParam = 99;
1178 break;
1179 case RTF_NOFWORDS:
1180 aName = "WordCount";
1181 break;
1182 case RTF_NOFCHARS:
1183 aName = "CharacterCount";
1184 break;
1185 case RTF_NOFCHARSWS:
1186 aName = "NonWhitespaceCharacterCount";
1187 break;
1188 default:
1189 break;
1191 if (!aName.isEmpty())
1193 aSeq[aName] <<= sal_Int32(nParam);
1194 m_xDocumentProperties->setDocumentStatistics(aSeq.getAsConstNamedValueList());
1197 break;
1198 case RTF_VERSION:
1199 if (m_xDocumentProperties.is())
1200 m_xDocumentProperties->setEditingCycles(nParam);
1201 break;
1202 case RTF_VERN:
1203 // Ignore this for now, later the RTF writer version could be used to add hacks for older buggy writers.
1204 break;
1205 case RTF_FTNSTART:
1206 putNestedSprm(m_aDefaultState.getParagraphSprms(),
1207 NS_ooxml::LN_EG_SectPrContents_footnotePr,
1208 NS_ooxml::LN_EG_FtnEdnNumProps_numStart, pIntValue);
1209 break;
1210 case RTF_AFTNSTART:
1211 putNestedSprm(m_aDefaultState.getParagraphSprms(),
1212 NS_ooxml::LN_EG_SectPrContents_endnotePr,
1213 NS_ooxml::LN_EG_FtnEdnNumProps_numStart, pIntValue);
1214 break;
1215 case RTF_DFRMTXTX:
1216 m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_hSpace, nParam);
1217 break;
1218 case RTF_DFRMTXTY:
1219 m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_vSpace, nParam);
1220 break;
1221 case RTF_DXFRTEXT:
1223 m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_hSpace, nParam);
1224 m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_vSpace, nParam);
1226 break;
1227 case RTF_FLYVERT:
1229 RTFVertOrient aVertOrient(nParam);
1230 m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign,
1231 aVertOrient.GetAlign());
1232 m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_vAnchor,
1233 aVertOrient.GetAnchor());
1235 break;
1236 case RTF_FLYHORZ:
1238 RTFHoriOrient aHoriOrient(nParam);
1239 m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_xAlign,
1240 aHoriOrient.GetAlign());
1241 m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_hAnchor,
1242 aHoriOrient.GetAnchor());
1244 break;
1245 case RTF_FLYANCHOR:
1246 break;
1247 case RTF_WMETAFILE:
1248 m_aStates.top().getPicture().eWMetafile = nParam;
1249 break;
1250 case RTF_SB:
1251 putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_spacing,
1252 NS_ooxml::LN_CT_Spacing_before, pIntValue);
1253 break;
1254 case RTF_SA:
1255 putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_spacing,
1256 NS_ooxml::LN_CT_Spacing_after, pIntValue);
1257 break;
1258 case RTF_DPX:
1259 m_aStates.top().getDrawingObject().setLeft(convertTwipToMm100(nParam));
1260 break;
1261 case RTF_DPY:
1262 m_aStates.top().getDrawingObject().setTop(convertTwipToMm100(nParam));
1263 break;
1264 case RTF_DPXSIZE:
1265 m_aStates.top().getDrawingObject().setRight(convertTwipToMm100(nParam));
1266 break;
1267 case RTF_DPYSIZE:
1268 m_aStates.top().getDrawingObject().setBottom(convertTwipToMm100(nParam));
1269 break;
1270 case RTF_PNSTART:
1271 m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Lvl_start, pIntValue);
1272 break;
1273 case RTF_PNF:
1275 auto pValue = new RTFValue(m_aFontNames[getFontIndex(nParam)]);
1276 RTFSprms aAttributes;
1277 aAttributes.set(NS_ooxml::LN_CT_Fonts_ascii, pValue);
1278 putNestedSprm(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_Lvl_rPr,
1279 NS_ooxml::LN_EG_RPrBase_rFonts, new RTFValue(aAttributes));
1281 break;
1282 case RTF_VIEWSCALE:
1283 m_aSettingsTableAttributes.set(NS_ooxml::LN_CT_Zoom_percent, pIntValue);
1284 break;
1285 case RTF_BIN:
1287 m_aStates.top().setInternalState(RTFInternalState::BIN);
1288 m_aStates.top().setBinaryToRead(nParam);
1290 break;
1291 case RTF_DPLINECOR:
1292 m_aStates.top().getDrawingObject().setLineColorR(nParam);
1293 m_aStates.top().getDrawingObject().setHasLineColor(true);
1294 break;
1295 case RTF_DPLINECOG:
1296 m_aStates.top().getDrawingObject().setLineColorG(nParam);
1297 m_aStates.top().getDrawingObject().setHasLineColor(true);
1298 break;
1299 case RTF_DPLINECOB:
1300 m_aStates.top().getDrawingObject().setLineColorB(nParam);
1301 m_aStates.top().getDrawingObject().setHasLineColor(true);
1302 break;
1303 case RTF_DPFILLBGCR:
1304 m_aStates.top().getDrawingObject().setFillColorR(nParam);
1305 m_aStates.top().getDrawingObject().setHasFillColor(true);
1306 break;
1307 case RTF_DPFILLBGCG:
1308 m_aStates.top().getDrawingObject().setFillColorG(nParam);
1309 m_aStates.top().getDrawingObject().setHasFillColor(true);
1310 break;
1311 case RTF_DPFILLBGCB:
1312 m_aStates.top().getDrawingObject().setFillColorB(nParam);
1313 m_aStates.top().getDrawingObject().setHasFillColor(true);
1314 break;
1315 case RTF_CLSHDNG:
1317 int nValue = -1;
1318 switch (nParam)
1320 case 500:
1321 nValue = NS_ooxml::LN_Value_ST_Shd_pct5;
1322 break;
1323 case 1000:
1324 nValue = NS_ooxml::LN_Value_ST_Shd_pct10;
1325 break;
1326 case 1200:
1327 nValue = NS_ooxml::LN_Value_ST_Shd_pct12;
1328 break;
1329 case 1500:
1330 nValue = NS_ooxml::LN_Value_ST_Shd_pct15;
1331 break;
1332 case 2000:
1333 nValue = NS_ooxml::LN_Value_ST_Shd_pct20;
1334 break;
1335 case 2500:
1336 nValue = NS_ooxml::LN_Value_ST_Shd_pct25;
1337 break;
1338 case 3000:
1339 nValue = NS_ooxml::LN_Value_ST_Shd_pct30;
1340 break;
1341 case 3500:
1342 nValue = NS_ooxml::LN_Value_ST_Shd_pct35;
1343 break;
1344 case 3700:
1345 nValue = NS_ooxml::LN_Value_ST_Shd_pct37;
1346 break;
1347 case 4000:
1348 nValue = NS_ooxml::LN_Value_ST_Shd_pct40;
1349 break;
1350 case 4500:
1351 nValue = NS_ooxml::LN_Value_ST_Shd_pct45;
1352 break;
1353 case 5000:
1354 nValue = NS_ooxml::LN_Value_ST_Shd_pct50;
1355 break;
1356 case 5500:
1357 nValue = NS_ooxml::LN_Value_ST_Shd_pct55;
1358 break;
1359 case 6000:
1360 nValue = NS_ooxml::LN_Value_ST_Shd_pct60;
1361 break;
1362 case 6200:
1363 nValue = NS_ooxml::LN_Value_ST_Shd_pct62;
1364 break;
1365 case 6500:
1366 nValue = NS_ooxml::LN_Value_ST_Shd_pct65;
1367 break;
1368 case 7000:
1369 nValue = NS_ooxml::LN_Value_ST_Shd_pct70;
1370 break;
1371 case 7500:
1372 nValue = NS_ooxml::LN_Value_ST_Shd_pct75;
1373 break;
1374 case 8000:
1375 nValue = NS_ooxml::LN_Value_ST_Shd_pct80;
1376 break;
1377 case 8500:
1378 nValue = NS_ooxml::LN_Value_ST_Shd_pct85;
1379 break;
1380 case 8700:
1381 nValue = NS_ooxml::LN_Value_ST_Shd_pct87;
1382 break;
1383 case 9000:
1384 nValue = NS_ooxml::LN_Value_ST_Shd_pct90;
1385 break;
1386 case 9500:
1387 nValue = NS_ooxml::LN_Value_ST_Shd_pct95;
1388 break;
1389 default:
1390 break;
1392 if (nValue != -1)
1393 putNestedAttribute(m_aStates.top().getTableCellSprms(),
1394 NS_ooxml::LN_CT_TcPrBase_shd, NS_ooxml::LN_CT_Shd_val,
1395 new RTFValue(nValue));
1397 break;
1398 case RTF_DODHGT:
1399 m_aStates.top().getDrawingObject().setDhgt(nParam);
1400 break;
1401 case RTF_DPPOLYCOUNT:
1402 if (nParam >= 0)
1404 m_aStates.top().getDrawingObject().setPolyLineCount(nParam);
1406 break;
1407 case RTF_DPPTX:
1409 RTFDrawingObject& rDrawingObject = m_aStates.top().getDrawingObject();
1411 if (rDrawingObject.getPolyLinePoints().empty())
1412 dispatchValue(RTF_DPPOLYCOUNT, 2);
1414 rDrawingObject.getPolyLinePoints().emplace_back(
1415 awt::Point(convertTwipToMm100(nParam), 0));
1417 break;
1418 case RTF_DPPTY:
1420 RTFDrawingObject& rDrawingObject = m_aStates.top().getDrawingObject();
1421 if (!rDrawingObject.getPolyLinePoints().empty())
1423 rDrawingObject.getPolyLinePoints().back().Y = convertTwipToMm100(nParam);
1424 rDrawingObject.setPolyLineCount(rDrawingObject.getPolyLineCount() - 1);
1425 if (rDrawingObject.getPolyLineCount() == 0 && rDrawingObject.getPropertySet().is())
1427 uno::Sequence<uno::Sequence<awt::Point>> aPointSequenceSequence
1428 = { comphelper::containerToSequence(rDrawingObject.getPolyLinePoints()) };
1429 rDrawingObject.getPropertySet()->setPropertyValue(
1430 "PolyPolygon", uno::Any(aPointSequenceSequence));
1434 break;
1435 case RTF_SHPFBLWTXT:
1436 // Shape is below text -> send it to the background.
1437 m_aStates.top().getShape().setInBackground(nParam != 0);
1438 break;
1439 case RTF_CLPADB:
1440 case RTF_CLPADL:
1441 case RTF_CLPADR:
1442 case RTF_CLPADT:
1444 RTFSprms aAttributes;
1445 aAttributes.set(NS_ooxml::LN_CT_TblWidth_type,
1446 new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa));
1447 aAttributes.set(NS_ooxml::LN_CT_TblWidth_w, new RTFValue(nParam));
1448 // Top and left is swapped, that's what Word does.
1449 switch (nKeyword)
1451 case RTF_CLPADB:
1452 nSprm = NS_ooxml::LN_CT_TcMar_bottom;
1453 break;
1454 case RTF_CLPADL:
1455 nSprm = NS_ooxml::LN_CT_TcMar_top;
1456 break;
1457 case RTF_CLPADR:
1458 nSprm = NS_ooxml::LN_CT_TcMar_right;
1459 break;
1460 case RTF_CLPADT:
1461 nSprm = NS_ooxml::LN_CT_TcMar_left;
1462 break;
1463 default:
1464 break;
1466 putNestedSprm(m_aStates.top().getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcMar,
1467 nSprm, new RTFValue(aAttributes));
1469 break;
1470 case RTF_TRPADDFB:
1471 case RTF_TRPADDFL:
1472 case RTF_TRPADDFR:
1473 case RTF_TRPADDFT:
1475 RTFSprms aAttributes;
1476 switch (nParam)
1478 case 3:
1479 aAttributes.set(NS_ooxml::LN_CT_TblWidth_type,
1480 new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa));
1481 break;
1483 switch (nKeyword)
1485 case RTF_TRPADDFB:
1486 nSprm = NS_ooxml::LN_CT_TcMar_bottom;
1487 break;
1488 case RTF_TRPADDFL:
1489 nSprm = NS_ooxml::LN_CT_TcMar_left;
1490 break;
1491 case RTF_TRPADDFR:
1492 nSprm = NS_ooxml::LN_CT_TcMar_right;
1493 break;
1494 case RTF_TRPADDFT:
1495 nSprm = NS_ooxml::LN_CT_TcMar_top;
1496 break;
1497 default:
1498 break;
1500 putNestedAttribute(m_aStates.top().getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcMar,
1501 nSprm, new RTFValue(aAttributes));
1502 putNestedAttribute(m_aDefaultState.getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcMar,
1503 nSprm, new RTFValue(aAttributes));
1505 break;
1506 case RTF_TRPADDB:
1507 case RTF_TRPADDL:
1508 case RTF_TRPADDR:
1509 case RTF_TRPADDT:
1511 RTFSprms aAttributes;
1512 aAttributes.set(NS_ooxml::LN_CT_TblWidth_w, new RTFValue(nParam));
1513 switch (nKeyword)
1515 case RTF_TRPADDB:
1516 nSprm = NS_ooxml::LN_CT_TcMar_bottom;
1517 break;
1518 case RTF_TRPADDL:
1519 nSprm = NS_ooxml::LN_CT_TcMar_left;
1520 break;
1521 case RTF_TRPADDR:
1522 nSprm = NS_ooxml::LN_CT_TcMar_right;
1523 break;
1524 case RTF_TRPADDT:
1525 nSprm = NS_ooxml::LN_CT_TcMar_top;
1526 break;
1527 default:
1528 break;
1530 putNestedSprm(m_aStates.top().getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcMar,
1531 nSprm, new RTFValue(aAttributes));
1532 putNestedSprm(m_aDefaultState.getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcMar,
1533 nSprm, new RTFValue(aAttributes));
1535 break;
1536 case RTF_FI:
1538 if (m_aStates.top().getDestination() == Destination::LISTLEVEL)
1540 if (m_aStates.top().getLevelNumbersValid())
1541 putNestedAttribute(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_PPrBase_ind,
1542 NS_ooxml::LN_CT_Ind_firstLine, pIntValue);
1543 else
1544 m_aInvalidListLevelFirstIndents[m_nListLevel] = nParam;
1546 else
1547 putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind,
1548 NS_ooxml::LN_CT_Ind_firstLine, pIntValue);
1549 break;
1551 case RTF_LI:
1553 if (m_aStates.top().getDestination() == Destination::LISTLEVEL)
1555 if (m_aStates.top().getLevelNumbersValid())
1556 putNestedAttribute(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_PPrBase_ind,
1557 NS_ooxml::LN_CT_Ind_left, pIntValue);
1559 else
1561 putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind,
1562 NS_ooxml::LN_CT_Ind_left, pIntValue);
1564 // It turns out \li should reset the \fi inherited from the stylesheet.
1565 // So set the direct formatting to zero, if we don't have such direct formatting yet.
1566 putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind,
1567 NS_ooxml::LN_CT_Ind_firstLine, new RTFValue(0),
1568 RTFOverwrite::NO_IGNORE);
1570 break;
1571 case RTF_RI:
1572 putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind,
1573 NS_ooxml::LN_CT_Ind_right, pIntValue);
1574 break;
1575 case RTF_LIN:
1576 putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind,
1577 NS_ooxml::LN_CT_Ind_start, pIntValue);
1578 break;
1579 case RTF_RIN:
1580 putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind,
1581 NS_ooxml::LN_CT_Ind_end, pIntValue);
1582 break;
1583 case RTF_OUTLINELEVEL:
1584 m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_outlineLvl, pIntValue);
1585 break;
1586 case RTF_TRGAPH:
1587 // Half of the space between the cells of a table row: default left/right table cell margin.
1588 if (nParam > 0)
1590 RTFSprms aAttributes;
1591 aAttributes.set(NS_ooxml::LN_CT_TblWidth_type,
1592 new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa));
1593 aAttributes.set(NS_ooxml::LN_CT_TblWidth_w, pIntValue);
1594 putNestedSprm(m_aStates.top().getTableRowSprms(),
1595 NS_ooxml::LN_CT_TblPrBase_tblCellMar, NS_ooxml::LN_CT_TblCellMar_left,
1596 new RTFValue(aAttributes));
1597 putNestedSprm(m_aStates.top().getTableRowSprms(),
1598 NS_ooxml::LN_CT_TblPrBase_tblCellMar,
1599 NS_ooxml::LN_CT_TblCellMar_right, new RTFValue(aAttributes));
1601 break;
1602 case RTF_TRFTSWIDTH:
1603 putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblW,
1604 NS_ooxml::LN_CT_TblWidth_type, pIntValue);
1605 break;
1606 case RTF_TRWWIDTH:
1607 putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblW,
1608 NS_ooxml::LN_CT_TblWidth_w, pIntValue);
1609 break;
1610 case RTF_PROPTYPE:
1612 switch (nParam)
1614 case 3:
1615 m_aStates.top().setPropType(cppu::UnoType<sal_Int32>::get());
1616 break;
1617 case 5:
1618 m_aStates.top().setPropType(cppu::UnoType<double>::get());
1619 break;
1620 case 11:
1621 m_aStates.top().setPropType(cppu::UnoType<bool>::get());
1622 break;
1623 case 30:
1624 m_aStates.top().setPropType(cppu::UnoType<OUString>::get());
1625 break;
1626 case 64:
1627 m_aStates.top().setPropType(cppu::UnoType<util::DateTime>::get());
1628 break;
1631 break;
1632 case RTF_DIBITMAP:
1633 m_aStates.top().getPicture().eStyle = RTFBmpStyle::DIBITMAP;
1634 break;
1635 case RTF_TRWWIDTHA:
1636 m_aStates.top().setTableRowWidthAfter(nParam);
1637 break;
1638 case RTF_ANIMTEXT:
1640 nId = 0;
1641 switch (nParam)
1643 case 0:
1644 nId = NS_ooxml::LN_Value_ST_TextEffect_none;
1645 break;
1646 case 2:
1647 nId = NS_ooxml::LN_Value_ST_TextEffect_blinkBackground;
1648 break;
1651 if (nId > 0)
1652 m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_effect,
1653 new RTFValue(nId));
1654 break;
1656 case RTF_VIEWBKSP:
1658 m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_displayBackgroundShape, pIntValue);
1659 // Send this token immediately, if it only appears before the first
1660 // run, it will be too late, we ignored the background shape already by then.
1661 outputSettingsTable();
1662 break;
1664 case RTF_STEXTFLOW:
1666 nId = 0;
1667 switch (nParam)
1669 case 0:
1670 nId = NS_ooxml::LN_Value_ST_TextDirection_lrTb;
1671 break;
1672 case 1:
1673 nId = NS_ooxml::LN_Value_ST_TextDirection_tbRl;
1674 break;
1677 if (nId > 0)
1679 m_aStates.top().getSectionSprms().set(NS_ooxml::LN_EG_SectPrContents_textDirection,
1680 new RTFValue(nId));
1683 break;
1684 default:
1686 SAL_INFO("writerfilter", "TODO handle value '" << keywordToString(nKeyword) << "'");
1687 aSkip.setParsed(false);
1689 break;
1691 return RTFError::OK;
1694 } // namespace rtftok
1695 } // namespace writerfilter
1697 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */