lok: vcl: fix multiple floatwin removal case more robustly.
[LibreOffice.git] / writerfilter / source / rtftok / rtfdispatchvalue.cxx
blob72fd4802a601b9cf7b5b36fad36fa20a337f597d
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().aTableSprms.set(nSprm, pIntValue);
160 return RTFError::OK;
162 // Trivial character sprms.
163 switch (nKeyword)
165 case RTF_FS:
166 case RTF_AFS:
167 nSprm = (m_aStates.top().isRightToLeft
168 || m_aStates.top().eRunType == RTFParserState::RunType::HICH)
169 ? NS_ooxml::LN_EG_RPrBase_szCs
170 : NS_ooxml::LN_EG_RPrBase_sz;
171 break;
172 case RTF_EXPNDTW:
173 nSprm = NS_ooxml::LN_EG_RPrBase_spacing;
174 break;
175 case RTF_KERNING:
176 nSprm = NS_ooxml::LN_EG_RPrBase_kern;
177 break;
178 case RTF_CHARSCALEX:
179 nSprm = NS_ooxml::LN_EG_RPrBase_w;
180 break;
181 default:
182 break;
184 if (nSprm > 0)
186 m_aStates.top().aCharacterSprms.set(nSprm, pIntValue);
187 return RTFError::OK;
189 // Trivial character attributes.
190 switch (nKeyword)
192 case RTF_LANG:
193 case RTF_ALANG:
194 if (m_aStates.top().isRightToLeft
195 || m_aStates.top().eRunType == RTFParserState::RunType::HICH)
197 nSprm = NS_ooxml::LN_CT_Language_bidi;
199 else if (m_aStates.top().eRunType == RTFParserState::RunType::DBCH)
201 nSprm = NS_ooxml::LN_CT_Language_eastAsia;
203 else
205 assert(m_aStates.top().eRunType == RTFParserState::RunType::LOCH);
206 nSprm = NS_ooxml::LN_CT_Language_val;
208 break;
209 case RTF_LANGFE: // this one is always CJK apparently
210 nSprm = NS_ooxml::LN_CT_Language_eastAsia;
211 break;
212 default:
213 break;
215 if (nSprm > 0)
217 LanguageTag aTag((LanguageType(static_cast<sal_uInt16>(nParam))));
218 auto pValue = new RTFValue(aTag.getBcp47());
219 putNestedAttribute(m_aStates.top().aCharacterSprms, NS_ooxml::LN_EG_RPrBase_lang, nSprm,
220 pValue);
221 // Language is a character property, but we should store it at a paragraph level as well for fields.
222 if (nKeyword == RTF_LANG && m_bNeedPap)
223 putNestedAttribute(m_aStates.top().aParagraphSprms, NS_ooxml::LN_EG_RPrBase_lang, nSprm,
224 pValue);
225 return RTFError::OK;
227 // Trivial paragraph sprms.
228 switch (nKeyword)
230 case RTF_ITAP:
231 nSprm = NS_ooxml::LN_tblDepth;
232 // tdf#117268: If \itap0 is encountered inside tables (between \cellxN and \cell), then
233 // use the default value (1), as Word apparently does
234 if (nParam == 0 && (m_nTopLevelCells != 0 || m_nNestedCells != 0))
236 nParam = 1;
237 pIntValue = new RTFValue(nParam);
239 break;
240 default:
241 break;
243 if (nSprm > 0)
245 m_aStates.top().aParagraphSprms.set(nSprm, pIntValue);
246 if (nKeyword == RTF_ITAP && nParam > 0)
248 while (m_aTableBufferStack.size() < sal::static_int_cast<std::size_t>(nParam))
250 m_aTableBufferStack.emplace_back(RTFBuffer_t());
252 // Invalid tables may omit INTBL after ITAP
253 dispatchFlag(RTF_INTBL); // sets newly pushed buffer as current
254 assert(m_aStates.top().pCurrentBuffer == &m_aTableBufferStack.back());
256 return RTFError::OK;
259 // Info group.
260 switch (nKeyword)
262 case RTF_YR:
264 m_aStates.top().nYear = nParam;
265 nSprm = 1;
267 break;
268 case RTF_MO:
270 m_aStates.top().nMonth = nParam;
271 nSprm = 1;
273 break;
274 case RTF_DY:
276 m_aStates.top().nDay = nParam;
277 nSprm = 1;
279 break;
280 case RTF_HR:
282 m_aStates.top().nHour = nParam;
283 nSprm = 1;
285 break;
286 case RTF_MIN:
288 m_aStates.top().nMinute = nParam;
289 nSprm = 1;
291 break;
292 default:
293 break;
295 if (nSprm > 0)
296 return RTFError::OK;
298 // Frame size / position.
299 Id nId = 0;
300 switch (nKeyword)
302 case RTF_ABSW:
303 nId = NS_ooxml::LN_CT_FramePr_w;
304 break;
305 case RTF_ABSH:
306 nId = NS_ooxml::LN_CT_FramePr_h;
307 break;
308 case RTF_POSX:
310 nId = NS_ooxml::LN_CT_FramePr_x;
311 m_aStates.top().aFrame.setSprm(NS_ooxml::LN_CT_FramePr_xAlign, 0);
313 break;
314 case RTF_POSY:
316 nId = NS_ooxml::LN_CT_FramePr_y;
317 m_aStates.top().aFrame.setSprm(NS_ooxml::LN_CT_FramePr_yAlign, 0);
319 break;
320 default:
321 break;
324 if (nId > 0)
326 m_bNeedPap = true;
327 // Don't try to support text frames inside tables for now.
328 if (m_aStates.top().pCurrentBuffer != &m_aTableBufferStack.back())
329 m_aStates.top().aFrame.setSprm(nId, nParam);
331 return RTFError::OK;
334 // Then check for the more complex ones.
335 switch (nKeyword)
337 case RTF_F:
338 case RTF_AF:
339 if (m_aStates.top().isRightToLeft
340 || m_aStates.top().eRunType == RTFParserState::RunType::HICH)
342 nSprm = NS_ooxml::LN_CT_Fonts_cs;
344 else if (m_aStates.top().eRunType == RTFParserState::RunType::DBCH)
346 nSprm = NS_ooxml::LN_CT_Fonts_eastAsia;
348 else
350 assert(m_aStates.top().eRunType == RTFParserState::RunType::LOCH);
351 nSprm = NS_ooxml::LN_CT_Fonts_ascii;
353 if (m_aStates.top().eDestination == Destination::FONTTABLE
354 || m_aStates.top().eDestination == Destination::FONTENTRY)
356 m_aFontIndexes.push_back(nParam);
357 m_nCurrentFontIndex = getFontIndex(nParam);
359 else if (m_aStates.top().eDestination == Destination::LISTLEVEL)
361 RTFSprms aFontAttributes;
362 aFontAttributes.set(nSprm, new RTFValue(m_aFontNames[getFontIndex(nParam)]));
363 RTFSprms aRunPropsSprms;
364 aRunPropsSprms.set(NS_ooxml::LN_EG_RPrBase_rFonts, new RTFValue(aFontAttributes));
365 m_aStates.top().aTableSprms.set(NS_ooxml::LN_CT_Lvl_rPr,
366 new RTFValue(RTFSprms(), aRunPropsSprms),
367 RTFOverwrite::NO_APPEND);
369 else
371 m_nCurrentFontIndex = getFontIndex(nParam);
372 auto pValue = new RTFValue(getFontName(m_nCurrentFontIndex));
373 putNestedAttribute(m_aStates.top().aCharacterSprms, NS_ooxml::LN_EG_RPrBase_rFonts,
374 nSprm, pValue);
375 if (nKeyword == RTF_F)
376 m_aStates.top().nCurrentEncoding = getEncoding(m_nCurrentFontIndex);
378 break;
379 case RTF_RED:
380 m_aStates.top().aCurrentColor.SetRed(nParam);
381 break;
382 case RTF_GREEN:
383 m_aStates.top().aCurrentColor.SetGreen(nParam);
384 break;
385 case RTF_BLUE:
386 m_aStates.top().aCurrentColor.SetBlue(nParam);
387 break;
388 case RTF_FCHARSET:
390 // we always send text to the domain mapper in OUString, so no
391 // need to send encoding info
392 int i;
393 for (i = 0; i < nRTFEncodings; i++)
395 if (aRTFEncodings[i].charset == nParam)
396 break;
398 if (i == nRTFEncodings)
399 // not found
400 return RTFError::OK;
402 m_nCurrentEncoding
403 = aRTFEncodings[i].codepage == 0 // Default (CP_ACP)
404 ? osl_getThreadTextEncoding()
405 : rtl_getTextEncodingFromWindowsCodePage(aRTFEncodings[i].codepage);
406 m_aStates.top().nCurrentEncoding = m_nCurrentEncoding;
408 break;
409 case RTF_ANSICPG:
410 case RTF_CPG:
412 rtl_TextEncoding nEncoding
413 = (nParam == 0)
414 ? utl_getWinTextEncodingFromLangStr(getLODefaultLanguage().toUtf8().getStr())
415 : rtl_getTextEncodingFromWindowsCodePage(nParam);
416 if (nKeyword == RTF_ANSICPG)
417 m_aDefaultState.nCurrentEncoding = nEncoding;
418 else
419 m_nCurrentEncoding = nEncoding;
420 m_aStates.top().nCurrentEncoding = nEncoding;
422 break;
423 case RTF_CF:
425 RTFSprms aAttributes;
426 auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam)));
427 aAttributes.set(NS_ooxml::LN_CT_Color_val, pValue);
428 m_aStates.top().aCharacterSprms.set(NS_ooxml::LN_EG_RPrBase_color,
429 new RTFValue(aAttributes));
431 break;
432 case RTF_S:
434 m_aStates.top().nCurrentStyleIndex = nParam;
436 if (m_aStates.top().eDestination == Destination::STYLESHEET
437 || m_aStates.top().eDestination == Destination::STYLEENTRY)
439 m_nCurrentStyleIndex = nParam;
440 auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_StyleType_paragraph);
441 m_aStates.top().aTableAttributes.set(NS_ooxml::LN_CT_Style_type,
442 pValue); // paragraph style
444 else
446 OUString aName = getStyleName(nParam);
447 if (!aName.isEmpty())
449 if (m_aStates.top().eDestination == Destination::LISTLEVEL)
450 m_aStates.top().aTableSprms.set(NS_ooxml::LN_CT_Lvl_pStyle,
451 new RTFValue(aName));
452 else
453 m_aStates.top().aParagraphSprms.set(NS_ooxml::LN_CT_PPrBase_pStyle,
454 new RTFValue(aName));
458 break;
459 case RTF_CS:
460 m_aStates.top().nCurrentCharacterStyleIndex = nParam;
461 if (m_aStates.top().eDestination == Destination::STYLESHEET
462 || m_aStates.top().eDestination == Destination::STYLEENTRY)
464 m_nCurrentStyleIndex = nParam;
465 auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_StyleType_character);
466 m_aStates.top().aTableAttributes.set(NS_ooxml::LN_CT_Style_type,
467 pValue); // character style
469 else
471 OUString aName = getStyleName(nParam);
472 if (!aName.isEmpty())
473 m_aStates.top().aCharacterSprms.set(NS_ooxml::LN_EG_RPrBase_rStyle,
474 new RTFValue(aName));
476 break;
477 case RTF_DS:
478 if (m_aStates.top().eDestination == Destination::STYLESHEET
479 || m_aStates.top().eDestination == Destination::STYLEENTRY)
481 m_nCurrentStyleIndex = nParam;
482 auto pValue = new RTFValue(0); // TODO no value in enum StyleType?
483 m_aStates.top().aTableAttributes.set(NS_ooxml::LN_CT_Style_type,
484 pValue); // section style
486 break;
487 case RTF_TS:
488 if (m_aStates.top().eDestination == Destination::STYLESHEET
489 || m_aStates.top().eDestination == Destination::STYLEENTRY)
491 m_nCurrentStyleIndex = nParam;
492 // 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
493 auto pValue = new RTFValue(0);
494 m_aStates.top().aTableAttributes.set(NS_ooxml::LN_CT_Style_type,
495 pValue); // table style
497 break;
498 case RTF_DEFF:
499 m_nDefaultFontIndex = nParam;
500 break;
501 case RTF_DEFLANG:
502 case RTF_ADEFLANG:
504 LanguageTag aTag((LanguageType(nParam)));
505 auto pValue = new RTFValue(aTag.getBcp47());
506 putNestedAttribute(m_aStates.top().aCharacterSprms,
507 (nKeyword == RTF_DEFLANG ? NS_ooxml::LN_EG_RPrBase_lang
508 : NS_ooxml::LN_CT_Language_bidi),
509 nSprm, pValue);
511 break;
512 case RTF_CHCBPAT:
514 auto pValue = new RTFValue(sal_uInt32(nParam ? getColorTable(nParam) : COL_AUTO));
515 putNestedAttribute(m_aStates.top().aCharacterSprms, NS_ooxml::LN_EG_RPrBase_shd,
516 NS_ooxml::LN_CT_Shd_fill, pValue);
518 break;
519 case RTF_CLCBPAT:
520 case RTF_CLCBPATRAW:
522 auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam)));
523 putNestedAttribute(m_aStates.top().aTableCellSprms, NS_ooxml::LN_CT_TcPrBase_shd,
524 NS_ooxml::LN_CT_Shd_fill, pValue);
526 break;
527 case RTF_CBPAT:
528 if (nParam)
530 auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam)));
531 putNestedAttribute(m_aStates.top().aParagraphSprms, NS_ooxml::LN_CT_PrBase_shd,
532 NS_ooxml::LN_CT_Shd_fill, pValue);
534 break;
535 case RTF_ULC:
537 auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam)));
538 m_aStates.top().aCharacterSprms.set(0x6877, pValue);
540 break;
541 case RTF_HIGHLIGHT:
543 auto pValue = new RTFValue(sal_uInt32(nParam ? getColorTable(nParam) : COL_AUTO));
544 m_aStates.top().aCharacterSprms.set(NS_ooxml::LN_EG_RPrBase_highlight, pValue);
546 break;
547 case RTF_UP:
548 case RTF_DN:
550 auto pValue = new RTFValue(nParam * (nKeyword == RTF_UP ? 1 : -1));
551 m_aStates.top().aCharacterSprms.set(NS_ooxml::LN_EG_RPrBase_position, pValue);
553 break;
554 case RTF_HORZVERT:
556 auto pValue = new RTFValue(int(true));
557 m_aStates.top().aCharacterAttributes.set(NS_ooxml::LN_CT_EastAsianLayout_vert, pValue);
558 if (nParam)
559 // rotate fits to a single line
560 m_aStates.top().aCharacterAttributes.set(
561 NS_ooxml::LN_CT_EastAsianLayout_vertCompress, pValue);
563 break;
564 case RTF_EXPND:
566 // Convert quarter-points to twentieths of a point
567 auto pValue = new RTFValue(nParam * 5);
568 m_aStates.top().aCharacterSprms.set(NS_ooxml::LN_EG_RPrBase_spacing, pValue);
570 break;
571 case RTF_TWOINONE:
573 auto pValue = new RTFValue(int(true));
574 m_aStates.top().aCharacterAttributes.set(NS_ooxml::LN_CT_EastAsianLayout_combine,
575 pValue);
576 nId = 0;
577 switch (nParam)
579 case 0:
580 nId = NS_ooxml::LN_Value_ST_CombineBrackets_none;
581 break;
582 case 1:
583 nId = NS_ooxml::LN_Value_ST_CombineBrackets_round;
584 break;
585 case 2:
586 nId = NS_ooxml::LN_Value_ST_CombineBrackets_square;
587 break;
588 case 3:
589 nId = NS_ooxml::LN_Value_ST_CombineBrackets_angle;
590 break;
591 case 4:
592 nId = NS_ooxml::LN_Value_ST_CombineBrackets_curly;
593 break;
595 if (nId > 0)
596 m_aStates.top().aCharacterAttributes.set(
597 NS_ooxml::LN_CT_EastAsianLayout_combineBrackets, new RTFValue(nId));
599 break;
600 case RTF_SL:
602 // This is similar to RTF_ABSH, negative value means 'exact', positive means 'at least'.
603 tools::SvRef<RTFValue> pValue(
604 new RTFValue(NS_ooxml::LN_Value_doc_ST_LineSpacingRule_atLeast));
605 if (nParam < 0)
607 pValue = new RTFValue(NS_ooxml::LN_Value_doc_ST_LineSpacingRule_exact);
608 pIntValue = new RTFValue(-nParam);
610 m_aStates.top().aParagraphAttributes.set(NS_ooxml::LN_CT_Spacing_lineRule, pValue);
611 m_aStates.top().aParagraphAttributes.set(NS_ooxml::LN_CT_Spacing_line, pIntValue);
613 break;
614 case RTF_SLMULT:
615 if (nParam > 0)
617 auto pValue = new RTFValue(NS_ooxml::LN_Value_doc_ST_LineSpacingRule_auto);
618 m_aStates.top().aParagraphAttributes.set(NS_ooxml::LN_CT_Spacing_lineRule, pValue);
620 break;
621 case RTF_BRDRW:
623 // dmapper expects it in 1/8 pt, we have it in twip - but avoid rounding 1 to 0
624 if (nParam > 1)
625 nParam = nParam * 2 / 5;
626 auto pValue = new RTFValue(nParam);
627 putBorderProperty(m_aStates, NS_ooxml::LN_CT_Border_sz, pValue);
629 break;
630 case RTF_BRDRCF:
632 auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam)));
633 putBorderProperty(m_aStates, NS_ooxml::LN_CT_Border_color, pValue);
635 break;
636 case RTF_BRSP:
638 // dmapper expects it in points, we have it in twip
639 auto pValue = new RTFValue(nParam / 20);
640 putBorderProperty(m_aStates, NS_ooxml::LN_CT_Border_space, pValue);
642 break;
643 case RTF_TX:
645 m_aStates.top().aTabAttributes.set(NS_ooxml::LN_CT_TabStop_pos, pIntValue);
646 auto pValue = new RTFValue(m_aStates.top().aTabAttributes);
647 if (m_aStates.top().eDestination == Destination::LISTLEVEL)
648 putNestedSprm(m_aStates.top().aTableSprms, NS_ooxml::LN_CT_PPrBase_tabs,
649 NS_ooxml::LN_CT_Tabs_tab, pValue);
650 else
651 putNestedSprm(m_aStates.top().aParagraphSprms, NS_ooxml::LN_CT_PPrBase_tabs,
652 NS_ooxml::LN_CT_Tabs_tab, pValue);
653 m_aStates.top().aTabAttributes.clear();
655 break;
656 case RTF_ILVL:
657 putNestedSprm(m_aStates.top().aParagraphSprms, NS_ooxml::LN_CT_PPrBase_numPr,
658 NS_ooxml::LN_CT_NumPr_ilvl, pIntValue);
659 break;
660 case RTF_LISTTEMPLATEID:
661 // This one is not referenced anywhere, so it's pointless to store it at the moment.
662 break;
663 case RTF_LISTID:
665 if (m_aStates.top().eDestination == Destination::LISTENTRY)
666 m_aStates.top().aTableAttributes.set(NS_ooxml::LN_CT_AbstractNum_abstractNumId,
667 pIntValue);
668 else if (m_aStates.top().eDestination == Destination::LISTOVERRIDEENTRY)
669 m_aStates.top().aTableSprms.set(NS_ooxml::LN_CT_Num_abstractNumId, pIntValue);
670 m_aStates.top().nCurrentListIndex = nParam;
672 break;
673 case RTF_LS:
675 if (m_aStates.top().eDestination == Destination::LISTOVERRIDEENTRY)
677 m_aStates.top().aTableAttributes.set(NS_ooxml::LN_CT_AbstractNum_nsid, pIntValue);
678 m_aStates.top().nCurrentListOverrideIndex = nParam;
680 else
682 // Insert at the start, so properties inherited from the list
683 // can be overridden by direct formatting. But still allow the
684 // case when old-style paragraph numbering is already
685 // tokenized.
686 putNestedSprm(m_aStates.top().aParagraphSprms, NS_ooxml::LN_CT_PPrBase_numPr,
687 NS_ooxml::LN_CT_NumPr_numId, pIntValue, RTFOverwrite::YES_PREPEND);
690 break;
691 case RTF_UC:
692 if ((SAL_MIN_INT16 <= nParam) && (nParam <= SAL_MAX_INT16))
693 m_aStates.top().nUc = nParam;
694 break;
695 case RTF_U:
696 // sal_Unicode is unsigned 16-bit, RTF may represent that as a
697 // signed SAL_MIN_INT16..SAL_MAX_INT16 or 0..SAL_MAX_UINT16. The
698 // static_cast() will do the right thing.
699 if ((SAL_MIN_INT16 <= nParam) && (nParam <= SAL_MAX_UINT16))
701 if (m_aStates.top().eDestination == Destination::LEVELNUMBERS)
703 if (nParam != ';')
704 m_aStates.top().aLevelNumbers.push_back(sal_Int32(nParam));
705 else
706 // ';' in \u form is not considered valid.
707 m_aStates.top().bLevelNumbersValid = false;
709 else
710 m_aUnicodeBuffer.append(static_cast<sal_Unicode>(nParam));
711 m_aStates.top().nCharsToSkip = m_aStates.top().nUc;
713 break;
714 case RTF_LEVELFOLLOW:
716 OUString sValue;
717 switch (nParam)
719 case 0:
720 sValue = "tab";
721 break;
722 case 1:
723 sValue = "space";
724 break;
725 case 2:
726 sValue = "nothing";
727 break;
729 if (!sValue.isEmpty())
730 m_aStates.top().aTableSprms.set(NS_ooxml::LN_CT_Lvl_suff, new RTFValue(sValue));
732 break;
733 case RTF_FPRQ:
735 sal_Int32 nValue = 0;
736 switch (nParam)
738 case 0:
739 nValue = NS_ooxml::LN_Value_ST_Pitch_default;
740 break;
741 case 1:
742 nValue = NS_ooxml::LN_Value_ST_Pitch_fixed;
743 break;
744 case 2:
745 nValue = NS_ooxml::LN_Value_ST_Pitch_variable;
746 break;
748 if (nValue)
750 RTFSprms aAttributes;
751 aAttributes.set(NS_ooxml::LN_CT_Pitch_val, new RTFValue(nValue));
752 m_aStates.top().aTableSprms.set(NS_ooxml::LN_CT_Font_pitch,
753 new RTFValue(aAttributes));
756 break;
757 case RTF_LISTOVERRIDECOUNT:
758 // Ignore this for now, the exporter always emits it with a zero parameter.
759 break;
760 case RTF_PICSCALEX:
761 m_aStates.top().aPicture.nScaleX = nParam;
762 break;
763 case RTF_PICSCALEY:
764 m_aStates.top().aPicture.nScaleY = nParam;
765 break;
766 case RTF_PICW:
767 m_aStates.top().aPicture.nWidth = nParam;
768 break;
769 case RTF_PICH:
770 m_aStates.top().aPicture.nHeight = nParam;
771 break;
772 case RTF_PICWGOAL:
773 m_aStates.top().aPicture.nGoalWidth = convertTwipToMm100(nParam);
774 break;
775 case RTF_PICHGOAL:
776 m_aStates.top().aPicture.nGoalHeight = convertTwipToMm100(nParam);
777 break;
778 case RTF_PICCROPL:
779 m_aStates.top().aPicture.nCropL = convertTwipToMm100(nParam);
780 break;
781 case RTF_PICCROPR:
782 m_aStates.top().aPicture.nCropR = convertTwipToMm100(nParam);
783 break;
784 case RTF_PICCROPT:
785 m_aStates.top().aPicture.nCropT = convertTwipToMm100(nParam);
786 break;
787 case RTF_PICCROPB:
788 m_aStates.top().aPicture.nCropB = convertTwipToMm100(nParam);
789 break;
790 case RTF_SHPWRK:
792 int nValue = 0;
793 switch (nParam)
795 case 0:
796 nValue = NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_bothSides;
797 break;
798 case 1:
799 nValue = NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_left;
800 break;
801 case 2:
802 nValue = NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_right;
803 break;
804 case 3:
805 nValue = NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_largest;
806 break;
807 default:
808 break;
810 auto pValue = new RTFValue(nValue);
811 RTFValue::Pointer_t pTight
812 = m_aStates.top().aCharacterSprms.find(NS_ooxml::LN_EG_WrapType_wrapTight);
813 if (pTight)
814 pTight->getAttributes().set(NS_ooxml::LN_CT_WrapTight_wrapText, pValue);
815 else
816 m_aStates.top().aCharacterAttributes.set(NS_ooxml::LN_CT_WrapSquare_wrapText,
817 pValue);
819 break;
820 case RTF_SHPWR:
822 switch (nParam)
824 case 1:
825 m_aStates.top().aShape.nWrap = text::WrapTextMode_NONE;
826 break;
827 case 2:
828 m_aStates.top().aShape.nWrap = text::WrapTextMode_PARALLEL;
829 break;
830 case 3:
831 m_aStates.top().aShape.nWrap = text::WrapTextMode_THROUGH;
832 m_aStates.top().aCharacterSprms.set(NS_ooxml::LN_EG_WrapType_wrapNone,
833 new RTFValue());
834 break;
835 case 4:
836 m_aStates.top().aShape.nWrap = text::WrapTextMode_PARALLEL;
837 m_aStates.top().aCharacterSprms.set(NS_ooxml::LN_EG_WrapType_wrapTight,
838 new RTFValue());
839 break;
840 case 5:
841 m_aStates.top().aShape.nWrap = text::WrapTextMode_THROUGH;
842 break;
845 break;
846 case RTF_CELLX:
848 int& rCurrentCellX((Destination::NESTEDTABLEPROPERTIES == m_aStates.top().eDestination)
849 ? m_nNestedCurrentCellX
850 : m_nTopLevelCurrentCellX);
851 int nCellX = nParam - rCurrentCellX;
852 const int COL_DFLT_WIDTH
853 = 41; // sw/source/filter/inc/wrtswtbl.hxx, minimal possible width of cells.
854 if (!nCellX)
855 nCellX = COL_DFLT_WIDTH;
857 // If there is a negative left margin, then the first cellx is relative to that.
858 RTFValue::Pointer_t pTblInd
859 = m_aStates.top().aTableRowSprms.find(NS_ooxml::LN_CT_TblPrBase_tblInd);
860 if (rCurrentCellX == 0 && pTblInd.get())
862 RTFValue::Pointer_t pWidth
863 = pTblInd->getAttributes().find(NS_ooxml::LN_CT_TblWidth_w);
864 if (pWidth.get() && pWidth->getInt() < 0)
865 nCellX = -1 * (pWidth->getInt() - nParam);
868 rCurrentCellX = nParam;
869 auto pXValue = new RTFValue(nCellX);
870 m_aStates.top().aTableRowSprms.set(NS_ooxml::LN_CT_TblGridBase_gridCol, pXValue,
871 RTFOverwrite::NO_APPEND);
872 if (Destination::NESTEDTABLEPROPERTIES == m_aStates.top().eDestination)
874 m_nNestedCells++;
875 // Push cell properties.
876 m_aNestedTableCellsSprms.push_back(m_aStates.top().aTableCellSprms);
877 m_aNestedTableCellsAttributes.push_back(m_aStates.top().aTableCellAttributes);
879 else
881 m_nTopLevelCells++;
882 // Push cell properties.
883 m_aTopLevelTableCellsSprms.push_back(m_aStates.top().aTableCellSprms);
884 m_aTopLevelTableCellsAttributes.push_back(m_aStates.top().aTableCellAttributes);
887 m_aStates.top().aTableCellSprms = m_aDefaultState.aTableCellSprms;
888 m_aStates.top().aTableCellAttributes = m_aDefaultState.aTableCellAttributes;
889 // We assume text after a row definition always belongs to the table, to handle text before the real INTBL token
890 dispatchFlag(RTF_INTBL);
891 if (!m_nCellxMax)
893 // Wasn't in table, but now is -> tblStart.
894 RTFSprms aAttributes;
895 RTFSprms aSprms;
896 aSprms.set(NS_ooxml::LN_tblStart, new RTFValue(1));
897 writerfilter::Reference<Properties>::Pointer_t pProperties
898 = new RTFReferenceProperties(aAttributes, aSprms);
899 Mapper().props(pProperties);
901 m_nCellxMax = std::max(m_nCellxMax, nParam);
903 break;
904 case RTF_TRRH:
906 OUString hRule("auto");
907 if (nParam < 0)
909 tools::SvRef<RTFValue> pAbsValue(new RTFValue(-nParam));
910 std::swap(pIntValue, pAbsValue);
912 hRule = "exact";
914 else if (nParam > 0)
915 hRule = "atLeast";
917 putNestedAttribute(m_aStates.top().aTableRowSprms, NS_ooxml::LN_CT_TrPrBase_trHeight,
918 NS_ooxml::LN_CT_Height_val, pIntValue);
920 auto pHRule = new RTFValue(hRule);
921 putNestedAttribute(m_aStates.top().aTableRowSprms, NS_ooxml::LN_CT_TrPrBase_trHeight,
922 NS_ooxml::LN_CT_Height_hRule, pHRule);
924 break;
925 case RTF_TRLEFT:
927 // the value is in twips
928 putNestedAttribute(m_aStates.top().aTableRowSprms, NS_ooxml::LN_CT_TblPrBase_tblInd,
929 NS_ooxml::LN_CT_TblWidth_type,
930 new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa));
931 putNestedAttribute(m_aStates.top().aTableRowSprms, NS_ooxml::LN_CT_TblPrBase_tblInd,
932 NS_ooxml::LN_CT_TblWidth_w, new RTFValue(nParam));
933 auto const aDestination = m_aStates.top().eDestination;
934 int& rCurrentTRLeft((Destination::NESTEDTABLEPROPERTIES == aDestination)
935 ? m_nNestedTRLeft
936 : m_nTopLevelTRLeft);
937 int& rCurrentCellX((Destination::NESTEDTABLEPROPERTIES == aDestination)
938 ? m_nNestedCurrentCellX
939 : m_nTopLevelCurrentCellX);
940 rCurrentTRLeft = rCurrentCellX = nParam;
942 break;
943 case RTF_COLS:
944 putNestedAttribute(m_aStates.top().aSectionSprms, NS_ooxml::LN_EG_SectPrContents_cols,
945 NS_ooxml::LN_CT_Columns_num, pIntValue);
946 break;
947 case RTF_COLSX:
948 putNestedAttribute(m_aStates.top().aSectionSprms, NS_ooxml::LN_EG_SectPrContents_cols,
949 NS_ooxml::LN_CT_Columns_space, pIntValue);
950 break;
951 case RTF_COLNO:
952 putNestedSprm(m_aStates.top().aSectionSprms, NS_ooxml::LN_EG_SectPrContents_cols,
953 NS_ooxml::LN_CT_Columns_col, pIntValue);
954 break;
955 case RTF_COLW:
956 case RTF_COLSR:
958 RTFSprms& rAttributes = getLastAttributes(m_aStates.top().aSectionSprms,
959 NS_ooxml::LN_EG_SectPrContents_cols);
960 rAttributes.set(
961 (nKeyword == RTF_COLW ? NS_ooxml::LN_CT_Column_w : NS_ooxml::LN_CT_Column_space),
962 pIntValue);
964 break;
965 case RTF_PAPERH:
966 putNestedAttribute(m_aDefaultState.aSectionSprms, NS_ooxml::LN_EG_SectPrContents_pgSz,
967 NS_ooxml::LN_CT_PageSz_h, pIntValue);
968 SAL_FALLTHROUGH; // set the default + current value
969 case RTF_PGHSXN:
970 putNestedAttribute(m_aStates.top().aSectionSprms, NS_ooxml::LN_EG_SectPrContents_pgSz,
971 NS_ooxml::LN_CT_PageSz_h, pIntValue);
972 break;
973 case RTF_PAPERW:
974 putNestedAttribute(m_aDefaultState.aSectionSprms, NS_ooxml::LN_EG_SectPrContents_pgSz,
975 NS_ooxml::LN_CT_PageSz_w, pIntValue);
976 SAL_FALLTHROUGH; // set the default + current value
977 case RTF_PGWSXN:
978 putNestedAttribute(m_aStates.top().aSectionSprms, NS_ooxml::LN_EG_SectPrContents_pgSz,
979 NS_ooxml::LN_CT_PageSz_w, pIntValue);
980 break;
981 case RTF_MARGL:
982 putNestedAttribute(m_aDefaultState.aSectionSprms, NS_ooxml::LN_EG_SectPrContents_pgMar,
983 NS_ooxml::LN_CT_PageMar_left, pIntValue);
984 SAL_FALLTHROUGH; // set the default + current value
985 case RTF_MARGLSXN:
986 putNestedAttribute(m_aStates.top().aSectionSprms, NS_ooxml::LN_EG_SectPrContents_pgMar,
987 NS_ooxml::LN_CT_PageMar_left, pIntValue);
988 break;
989 case RTF_MARGR:
990 putNestedAttribute(m_aDefaultState.aSectionSprms, NS_ooxml::LN_EG_SectPrContents_pgMar,
991 NS_ooxml::LN_CT_PageMar_right, pIntValue);
992 SAL_FALLTHROUGH; // set the default + current value
993 case RTF_MARGRSXN:
994 putNestedAttribute(m_aStates.top().aSectionSprms, NS_ooxml::LN_EG_SectPrContents_pgMar,
995 NS_ooxml::LN_CT_PageMar_right, pIntValue);
996 break;
997 case RTF_MARGT:
998 putNestedAttribute(m_aDefaultState.aSectionSprms, NS_ooxml::LN_EG_SectPrContents_pgMar,
999 NS_ooxml::LN_CT_PageMar_top, pIntValue);
1000 SAL_FALLTHROUGH; // set the default + current value
1001 case RTF_MARGTSXN:
1002 putNestedAttribute(m_aStates.top().aSectionSprms, NS_ooxml::LN_EG_SectPrContents_pgMar,
1003 NS_ooxml::LN_CT_PageMar_top, pIntValue);
1004 break;
1005 case RTF_MARGB:
1006 putNestedAttribute(m_aDefaultState.aSectionSprms, NS_ooxml::LN_EG_SectPrContents_pgMar,
1007 NS_ooxml::LN_CT_PageMar_bottom, pIntValue);
1008 SAL_FALLTHROUGH; // set the default + current value
1009 case RTF_MARGBSXN:
1010 putNestedAttribute(m_aStates.top().aSectionSprms, NS_ooxml::LN_EG_SectPrContents_pgMar,
1011 NS_ooxml::LN_CT_PageMar_bottom, pIntValue);
1012 break;
1013 case RTF_HEADERY:
1014 putNestedAttribute(m_aStates.top().aSectionSprms, NS_ooxml::LN_EG_SectPrContents_pgMar,
1015 NS_ooxml::LN_CT_PageMar_header, pIntValue);
1016 break;
1017 case RTF_FOOTERY:
1018 putNestedAttribute(m_aStates.top().aSectionSprms, NS_ooxml::LN_EG_SectPrContents_pgMar,
1019 NS_ooxml::LN_CT_PageMar_footer, pIntValue);
1020 break;
1021 case RTF_DEFTAB:
1022 m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_defaultTabStop, pIntValue);
1023 break;
1024 case RTF_LINEMOD:
1025 putNestedAttribute(m_aStates.top().aSectionSprms,
1026 NS_ooxml::LN_EG_SectPrContents_lnNumType,
1027 NS_ooxml::LN_CT_LineNumber_countBy, pIntValue);
1028 break;
1029 case RTF_LINEX:
1030 if (nParam)
1031 putNestedAttribute(m_aStates.top().aSectionSprms,
1032 NS_ooxml::LN_EG_SectPrContents_lnNumType,
1033 NS_ooxml::LN_CT_LineNumber_distance, pIntValue);
1034 break;
1035 case RTF_LINESTARTS:
1036 putNestedAttribute(m_aStates.top().aSectionSprms,
1037 NS_ooxml::LN_EG_SectPrContents_lnNumType,
1038 NS_ooxml::LN_CT_LineNumber_start, pIntValue);
1039 break;
1040 case RTF_REVAUTH:
1041 case RTF_REVAUTHDEL:
1043 auto pValue = new RTFValue(m_aAuthors[nParam]);
1044 putNestedAttribute(m_aStates.top().aCharacterSprms, NS_ooxml::LN_trackchange,
1045 NS_ooxml::LN_CT_TrackChange_author, pValue);
1047 break;
1048 case RTF_REVDTTM:
1049 case RTF_REVDTTMDEL:
1051 OUString aStr(
1052 OStringToOUString(DTTM22OString(nParam), m_aStates.top().nCurrentEncoding));
1053 auto pValue = new RTFValue(aStr);
1054 putNestedAttribute(m_aStates.top().aCharacterSprms, NS_ooxml::LN_trackchange,
1055 NS_ooxml::LN_CT_TrackChange_date, pValue);
1057 break;
1058 case RTF_SHPLEFT:
1059 m_aStates.top().aShape.nLeft = convertTwipToMm100(nParam);
1060 break;
1061 case RTF_SHPTOP:
1062 m_aStates.top().aShape.nTop = convertTwipToMm100(nParam);
1063 break;
1064 case RTF_SHPRIGHT:
1065 m_aStates.top().aShape.nRight = convertTwipToMm100(nParam);
1066 break;
1067 case RTF_SHPBOTTOM:
1068 m_aStates.top().aShape.nBottom = convertTwipToMm100(nParam);
1069 break;
1070 case RTF_SHPZ:
1071 m_aStates.top().aShape.oZ.reset(nParam);
1072 break;
1073 case RTF_FFTYPE:
1074 switch (nParam)
1076 case 0:
1077 m_nFormFieldType = RTFFormFieldType::TEXT;
1078 break;
1079 case 1:
1080 m_nFormFieldType = RTFFormFieldType::CHECKBOX;
1081 break;
1082 case 2:
1083 m_nFormFieldType = RTFFormFieldType::LIST;
1084 break;
1085 default:
1086 m_nFormFieldType = RTFFormFieldType::NONE;
1087 break;
1089 break;
1090 case RTF_FFDEFRES:
1091 if (m_nFormFieldType == RTFFormFieldType::CHECKBOX)
1092 m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFCheckBox_default, pIntValue);
1093 else if (m_nFormFieldType == RTFFormFieldType::LIST)
1094 m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFDDList_default, pIntValue);
1095 break;
1096 case RTF_FFRES:
1097 // 25 means undefined, see [MS-DOC] 2.9.79, FFDataBits.
1098 if (m_nFormFieldType == RTFFormFieldType::CHECKBOX && nParam != 25)
1099 m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFCheckBox_checked, pIntValue);
1100 else if (m_nFormFieldType == RTFFormFieldType::LIST)
1101 m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFDDList_result, pIntValue);
1102 break;
1103 case RTF_EDMINS:
1104 if (m_xDocumentProperties.is())
1106 // tdf#116851 some RTF may be malformed
1107 if (nParam < 0)
1108 nParam = -nParam;
1109 m_xDocumentProperties->setEditingDuration(nParam);
1111 break;
1112 case RTF_NOFPAGES:
1113 case RTF_NOFWORDS:
1114 case RTF_NOFCHARS:
1115 case RTF_NOFCHARSWS:
1116 if (m_xDocumentProperties.is())
1118 comphelper::SequenceAsHashMap aSeq = m_xDocumentProperties->getDocumentStatistics();
1119 OUString aName;
1120 switch (nKeyword)
1122 case RTF_NOFPAGES:
1123 aName = "PageCount";
1124 nParam = 99;
1125 break;
1126 case RTF_NOFWORDS:
1127 aName = "WordCount";
1128 break;
1129 case RTF_NOFCHARS:
1130 aName = "CharacterCount";
1131 break;
1132 case RTF_NOFCHARSWS:
1133 aName = "NonWhitespaceCharacterCount";
1134 break;
1135 default:
1136 break;
1138 if (!aName.isEmpty())
1140 aSeq[aName] <<= sal_Int32(nParam);
1141 m_xDocumentProperties->setDocumentStatistics(aSeq.getAsConstNamedValueList());
1144 break;
1145 case RTF_VERSION:
1146 if (m_xDocumentProperties.is())
1147 m_xDocumentProperties->setEditingCycles(nParam);
1148 break;
1149 case RTF_VERN:
1150 // Ignore this for now, later the RTF writer version could be used to add hacks for older buggy writers.
1151 break;
1152 case RTF_FTNSTART:
1153 putNestedSprm(m_aDefaultState.aParagraphSprms,
1154 NS_ooxml::LN_EG_SectPrContents_footnotePr,
1155 NS_ooxml::LN_EG_FtnEdnNumProps_numStart, pIntValue);
1156 break;
1157 case RTF_AFTNSTART:
1158 putNestedSprm(m_aDefaultState.aParagraphSprms, NS_ooxml::LN_EG_SectPrContents_endnotePr,
1159 NS_ooxml::LN_EG_FtnEdnNumProps_numStart, pIntValue);
1160 break;
1161 case RTF_DFRMTXTX:
1162 m_aStates.top().aFrame.setSprm(NS_ooxml::LN_CT_FramePr_hSpace, nParam);
1163 break;
1164 case RTF_DFRMTXTY:
1165 m_aStates.top().aFrame.setSprm(NS_ooxml::LN_CT_FramePr_vSpace, nParam);
1166 break;
1167 case RTF_DXFRTEXT:
1169 m_aStates.top().aFrame.setSprm(NS_ooxml::LN_CT_FramePr_hSpace, nParam);
1170 m_aStates.top().aFrame.setSprm(NS_ooxml::LN_CT_FramePr_vSpace, nParam);
1172 break;
1173 case RTF_FLYVERT:
1175 RTFVertOrient aVertOrient(nParam);
1176 m_aStates.top().aFrame.setSprm(NS_ooxml::LN_CT_FramePr_yAlign, aVertOrient.GetAlign());
1177 m_aStates.top().aFrame.setSprm(NS_ooxml::LN_CT_FramePr_vAnchor,
1178 aVertOrient.GetAnchor());
1180 break;
1181 case RTF_FLYHORZ:
1183 RTFHoriOrient aHoriOrient(nParam);
1184 m_aStates.top().aFrame.setSprm(NS_ooxml::LN_CT_FramePr_xAlign, aHoriOrient.GetAlign());
1185 m_aStates.top().aFrame.setSprm(NS_ooxml::LN_CT_FramePr_hAnchor,
1186 aHoriOrient.GetAnchor());
1188 break;
1189 case RTF_FLYANCHOR:
1190 break;
1191 case RTF_WMETAFILE:
1192 m_aStates.top().aPicture.eWMetafile = nParam;
1193 break;
1194 case RTF_SB:
1195 putNestedAttribute(m_aStates.top().aParagraphSprms, NS_ooxml::LN_CT_PPrBase_spacing,
1196 NS_ooxml::LN_CT_Spacing_before, pIntValue);
1197 break;
1198 case RTF_SA:
1199 putNestedAttribute(m_aStates.top().aParagraphSprms, NS_ooxml::LN_CT_PPrBase_spacing,
1200 NS_ooxml::LN_CT_Spacing_after, pIntValue);
1201 break;
1202 case RTF_DPX:
1203 m_aStates.top().aDrawingObject.nLeft = convertTwipToMm100(nParam);
1204 break;
1205 case RTF_DPY:
1206 m_aStates.top().aDrawingObject.nTop = convertTwipToMm100(nParam);
1207 break;
1208 case RTF_DPXSIZE:
1209 m_aStates.top().aDrawingObject.nRight = convertTwipToMm100(nParam);
1210 break;
1211 case RTF_DPYSIZE:
1212 m_aStates.top().aDrawingObject.nBottom = convertTwipToMm100(nParam);
1213 break;
1214 case RTF_PNSTART:
1215 m_aStates.top().aTableSprms.set(NS_ooxml::LN_CT_Lvl_start, pIntValue);
1216 break;
1217 case RTF_PNF:
1219 auto pValue = new RTFValue(m_aFontNames[getFontIndex(nParam)]);
1220 RTFSprms aAttributes;
1221 aAttributes.set(NS_ooxml::LN_CT_Fonts_ascii, pValue);
1222 putNestedSprm(m_aStates.top().aTableSprms, NS_ooxml::LN_CT_Lvl_rPr,
1223 NS_ooxml::LN_EG_RPrBase_rFonts, new RTFValue(aAttributes));
1225 break;
1226 case RTF_VIEWSCALE:
1227 m_aSettingsTableAttributes.set(NS_ooxml::LN_CT_Zoom_percent, pIntValue);
1228 break;
1229 case RTF_BIN:
1231 m_aStates.top().nInternalState = RTFInternalState::BIN;
1232 m_aStates.top().nBinaryToRead = nParam;
1234 break;
1235 case RTF_DPLINECOR:
1236 m_aStates.top().aDrawingObject.nLineColorR = nParam;
1237 m_aStates.top().aDrawingObject.bHasLineColor = true;
1238 break;
1239 case RTF_DPLINECOG:
1240 m_aStates.top().aDrawingObject.nLineColorG = nParam;
1241 m_aStates.top().aDrawingObject.bHasLineColor = true;
1242 break;
1243 case RTF_DPLINECOB:
1244 m_aStates.top().aDrawingObject.nLineColorB = nParam;
1245 m_aStates.top().aDrawingObject.bHasLineColor = true;
1246 break;
1247 case RTF_DPFILLBGCR:
1248 m_aStates.top().aDrawingObject.nFillColorR = nParam;
1249 m_aStates.top().aDrawingObject.bHasFillColor = true;
1250 break;
1251 case RTF_DPFILLBGCG:
1252 m_aStates.top().aDrawingObject.nFillColorG = nParam;
1253 m_aStates.top().aDrawingObject.bHasFillColor = true;
1254 break;
1255 case RTF_DPFILLBGCB:
1256 m_aStates.top().aDrawingObject.nFillColorB = nParam;
1257 m_aStates.top().aDrawingObject.bHasFillColor = true;
1258 break;
1259 case RTF_CLSHDNG:
1261 int nValue = -1;
1262 switch (nParam)
1264 case 500:
1265 nValue = NS_ooxml::LN_Value_ST_Shd_pct5;
1266 break;
1267 case 1000:
1268 nValue = NS_ooxml::LN_Value_ST_Shd_pct10;
1269 break;
1270 case 1200:
1271 nValue = NS_ooxml::LN_Value_ST_Shd_pct12;
1272 break;
1273 case 1500:
1274 nValue = NS_ooxml::LN_Value_ST_Shd_pct15;
1275 break;
1276 case 2000:
1277 nValue = NS_ooxml::LN_Value_ST_Shd_pct20;
1278 break;
1279 case 2500:
1280 nValue = NS_ooxml::LN_Value_ST_Shd_pct25;
1281 break;
1282 case 3000:
1283 nValue = NS_ooxml::LN_Value_ST_Shd_pct30;
1284 break;
1285 case 3500:
1286 nValue = NS_ooxml::LN_Value_ST_Shd_pct35;
1287 break;
1288 case 3700:
1289 nValue = NS_ooxml::LN_Value_ST_Shd_pct37;
1290 break;
1291 case 4000:
1292 nValue = NS_ooxml::LN_Value_ST_Shd_pct40;
1293 break;
1294 case 4500:
1295 nValue = NS_ooxml::LN_Value_ST_Shd_pct45;
1296 break;
1297 case 5000:
1298 nValue = NS_ooxml::LN_Value_ST_Shd_pct50;
1299 break;
1300 case 5500:
1301 nValue = NS_ooxml::LN_Value_ST_Shd_pct55;
1302 break;
1303 case 6000:
1304 nValue = NS_ooxml::LN_Value_ST_Shd_pct60;
1305 break;
1306 case 6200:
1307 nValue = NS_ooxml::LN_Value_ST_Shd_pct62;
1308 break;
1309 case 6500:
1310 nValue = NS_ooxml::LN_Value_ST_Shd_pct65;
1311 break;
1312 case 7000:
1313 nValue = NS_ooxml::LN_Value_ST_Shd_pct70;
1314 break;
1315 case 7500:
1316 nValue = NS_ooxml::LN_Value_ST_Shd_pct75;
1317 break;
1318 case 8000:
1319 nValue = NS_ooxml::LN_Value_ST_Shd_pct80;
1320 break;
1321 case 8500:
1322 nValue = NS_ooxml::LN_Value_ST_Shd_pct85;
1323 break;
1324 case 8700:
1325 nValue = NS_ooxml::LN_Value_ST_Shd_pct87;
1326 break;
1327 case 9000:
1328 nValue = NS_ooxml::LN_Value_ST_Shd_pct90;
1329 break;
1330 case 9500:
1331 nValue = NS_ooxml::LN_Value_ST_Shd_pct95;
1332 break;
1333 default:
1334 break;
1336 if (nValue != -1)
1337 putNestedAttribute(m_aStates.top().aTableCellSprms, NS_ooxml::LN_CT_TcPrBase_shd,
1338 NS_ooxml::LN_CT_Shd_val, new RTFValue(nValue));
1340 break;
1341 case RTF_DODHGT:
1342 m_aStates.top().aDrawingObject.nDhgt = nParam;
1343 break;
1344 case RTF_DPPOLYCOUNT:
1345 if (nParam >= 0)
1347 m_aStates.top().aDrawingObject.nPolyLineCount = nParam;
1349 break;
1350 case RTF_DPPTX:
1352 RTFDrawingObject& rDrawingObject = m_aStates.top().aDrawingObject;
1354 if (rDrawingObject.aPolyLinePoints.empty())
1355 dispatchValue(RTF_DPPOLYCOUNT, 2);
1357 rDrawingObject.aPolyLinePoints.emplace_back(awt::Point(convertTwipToMm100(nParam), 0));
1359 break;
1360 case RTF_DPPTY:
1362 RTFDrawingObject& rDrawingObject = m_aStates.top().aDrawingObject;
1363 if (!rDrawingObject.aPolyLinePoints.empty())
1365 rDrawingObject.aPolyLinePoints.back().Y = convertTwipToMm100(nParam);
1366 rDrawingObject.nPolyLineCount--;
1367 if (rDrawingObject.nPolyLineCount == 0 && rDrawingObject.xPropertySet.is())
1369 uno::Sequence<uno::Sequence<awt::Point>> aPointSequenceSequence
1370 = { comphelper::containerToSequence(rDrawingObject.aPolyLinePoints) };
1371 rDrawingObject.xPropertySet->setPropertyValue("PolyPolygon",
1372 uno::Any(aPointSequenceSequence));
1376 break;
1377 case RTF_SHPFBLWTXT:
1378 // Shape is below text -> send it to the background.
1379 m_aStates.top().aShape.bInBackground = nParam;
1380 break;
1381 case RTF_CLPADB:
1382 case RTF_CLPADL:
1383 case RTF_CLPADR:
1384 case RTF_CLPADT:
1386 RTFSprms aAttributes;
1387 aAttributes.set(NS_ooxml::LN_CT_TblWidth_type,
1388 new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa));
1389 aAttributes.set(NS_ooxml::LN_CT_TblWidth_w, new RTFValue(nParam));
1390 // Top and left is swapped, that's what Word does.
1391 switch (nKeyword)
1393 case RTF_CLPADB:
1394 nSprm = NS_ooxml::LN_CT_TcMar_bottom;
1395 break;
1396 case RTF_CLPADL:
1397 nSprm = NS_ooxml::LN_CT_TcMar_top;
1398 break;
1399 case RTF_CLPADR:
1400 nSprm = NS_ooxml::LN_CT_TcMar_right;
1401 break;
1402 case RTF_CLPADT:
1403 nSprm = NS_ooxml::LN_CT_TcMar_left;
1404 break;
1405 default:
1406 break;
1408 putNestedSprm(m_aStates.top().aTableCellSprms, NS_ooxml::LN_CT_TcPrBase_tcMar, nSprm,
1409 new RTFValue(aAttributes));
1411 break;
1412 case RTF_TRPADDFB:
1413 case RTF_TRPADDFL:
1414 case RTF_TRPADDFR:
1415 case RTF_TRPADDFT:
1417 RTFSprms aAttributes;
1418 switch (nParam)
1420 case 3:
1421 aAttributes.set(NS_ooxml::LN_CT_TblWidth_type,
1422 new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa));
1423 break;
1425 switch (nKeyword)
1427 case RTF_TRPADDFB:
1428 nSprm = NS_ooxml::LN_CT_TcMar_bottom;
1429 break;
1430 case RTF_TRPADDFL:
1431 nSprm = NS_ooxml::LN_CT_TcMar_left;
1432 break;
1433 case RTF_TRPADDFR:
1434 nSprm = NS_ooxml::LN_CT_TcMar_right;
1435 break;
1436 case RTF_TRPADDFT:
1437 nSprm = NS_ooxml::LN_CT_TcMar_top;
1438 break;
1439 default:
1440 break;
1442 putNestedAttribute(m_aStates.top().aTableCellSprms, NS_ooxml::LN_CT_TcPrBase_tcMar,
1443 nSprm, new RTFValue(aAttributes));
1444 putNestedAttribute(m_aDefaultState.aTableCellSprms, NS_ooxml::LN_CT_TcPrBase_tcMar,
1445 nSprm, new RTFValue(aAttributes));
1447 break;
1448 case RTF_TRPADDB:
1449 case RTF_TRPADDL:
1450 case RTF_TRPADDR:
1451 case RTF_TRPADDT:
1453 RTFSprms aAttributes;
1454 aAttributes.set(NS_ooxml::LN_CT_TblWidth_w, new RTFValue(nParam));
1455 switch (nKeyword)
1457 case RTF_TRPADDB:
1458 nSprm = NS_ooxml::LN_CT_TcMar_bottom;
1459 break;
1460 case RTF_TRPADDL:
1461 nSprm = NS_ooxml::LN_CT_TcMar_left;
1462 break;
1463 case RTF_TRPADDR:
1464 nSprm = NS_ooxml::LN_CT_TcMar_right;
1465 break;
1466 case RTF_TRPADDT:
1467 nSprm = NS_ooxml::LN_CT_TcMar_top;
1468 break;
1469 default:
1470 break;
1472 putNestedSprm(m_aStates.top().aTableCellSprms, NS_ooxml::LN_CT_TcPrBase_tcMar, nSprm,
1473 new RTFValue(aAttributes));
1474 putNestedSprm(m_aDefaultState.aTableCellSprms, NS_ooxml::LN_CT_TcPrBase_tcMar, nSprm,
1475 new RTFValue(aAttributes));
1477 break;
1478 case RTF_FI:
1480 if (m_aStates.top().eDestination == Destination::LISTLEVEL)
1482 if (m_aStates.top().bLevelNumbersValid)
1483 putNestedAttribute(m_aStates.top().aTableSprms, NS_ooxml::LN_CT_PPrBase_ind,
1484 NS_ooxml::LN_CT_Ind_firstLine, pIntValue);
1485 else
1486 m_aInvalidListLevelFirstIndents[m_nListLevel] = nParam;
1488 else
1489 putNestedAttribute(m_aStates.top().aParagraphSprms, NS_ooxml::LN_CT_PPrBase_ind,
1490 NS_ooxml::LN_CT_Ind_firstLine, pIntValue);
1491 break;
1493 case RTF_LI:
1495 if (m_aStates.top().eDestination == Destination::LISTLEVEL)
1497 if (m_aStates.top().bLevelNumbersValid)
1498 putNestedAttribute(m_aStates.top().aTableSprms, NS_ooxml::LN_CT_PPrBase_ind,
1499 NS_ooxml::LN_CT_Ind_left, pIntValue);
1501 else
1503 putNestedAttribute(m_aStates.top().aParagraphSprms, NS_ooxml::LN_CT_PPrBase_ind,
1504 NS_ooxml::LN_CT_Ind_left, pIntValue);
1506 // It turns out \li should reset the \fi inherited from the stylesheet.
1507 // So set the direct formatting to zero, if we don't have such direct formatting yet.
1508 putNestedAttribute(m_aStates.top().aParagraphSprms, NS_ooxml::LN_CT_PPrBase_ind,
1509 NS_ooxml::LN_CT_Ind_firstLine, new RTFValue(0),
1510 RTFOverwrite::NO_IGNORE);
1512 break;
1513 case RTF_RI:
1514 putNestedAttribute(m_aStates.top().aParagraphSprms, NS_ooxml::LN_CT_PPrBase_ind,
1515 NS_ooxml::LN_CT_Ind_right, pIntValue);
1516 break;
1517 case RTF_LIN:
1518 putNestedAttribute(m_aStates.top().aParagraphSprms, NS_ooxml::LN_CT_PPrBase_ind,
1519 NS_ooxml::LN_CT_Ind_start, pIntValue);
1520 break;
1521 case RTF_RIN:
1522 putNestedAttribute(m_aStates.top().aParagraphSprms, NS_ooxml::LN_CT_PPrBase_ind,
1523 NS_ooxml::LN_CT_Ind_end, pIntValue);
1524 break;
1525 case RTF_OUTLINELEVEL:
1526 m_aStates.top().aParagraphSprms.set(NS_ooxml::LN_CT_PPrBase_outlineLvl, pIntValue);
1527 break;
1528 case RTF_TRGAPH:
1529 // Half of the space between the cells of a table row: default left/right table cell margin.
1530 if (nParam > 0)
1532 RTFSprms aAttributes;
1533 aAttributes.set(NS_ooxml::LN_CT_TblWidth_type,
1534 new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa));
1535 aAttributes.set(NS_ooxml::LN_CT_TblWidth_w, pIntValue);
1536 putNestedSprm(m_aStates.top().aTableRowSprms, NS_ooxml::LN_CT_TblPrBase_tblCellMar,
1537 NS_ooxml::LN_CT_TblCellMar_left, new RTFValue(aAttributes));
1538 putNestedSprm(m_aStates.top().aTableRowSprms, NS_ooxml::LN_CT_TblPrBase_tblCellMar,
1539 NS_ooxml::LN_CT_TblCellMar_right, new RTFValue(aAttributes));
1541 break;
1542 case RTF_TRFTSWIDTH:
1543 putNestedAttribute(m_aStates.top().aTableRowSprms, NS_ooxml::LN_CT_TblPrBase_tblW,
1544 NS_ooxml::LN_CT_TblWidth_type, pIntValue);
1545 break;
1546 case RTF_TRWWIDTH:
1547 putNestedAttribute(m_aStates.top().aTableRowSprms, NS_ooxml::LN_CT_TblPrBase_tblW,
1548 NS_ooxml::LN_CT_TblWidth_w, pIntValue);
1549 break;
1550 case RTF_PROPTYPE:
1552 switch (nParam)
1554 case 3:
1555 m_aStates.top().aPropType = cppu::UnoType<sal_Int32>::get();
1556 break;
1557 case 5:
1558 m_aStates.top().aPropType = cppu::UnoType<double>::get();
1559 break;
1560 case 11:
1561 m_aStates.top().aPropType = cppu::UnoType<bool>::get();
1562 break;
1563 case 30:
1564 m_aStates.top().aPropType = cppu::UnoType<OUString>::get();
1565 break;
1566 case 64:
1567 m_aStates.top().aPropType = cppu::UnoType<util::DateTime>::get();
1568 break;
1571 break;
1572 case RTF_DIBITMAP:
1573 m_aStates.top().aPicture.eStyle = RTFBmpStyle::DIBITMAP;
1574 break;
1575 case RTF_TRWWIDTHA:
1576 m_aStates.top().nTableRowWidthAfter = nParam;
1577 break;
1578 case RTF_ANIMTEXT:
1580 nId = 0;
1581 switch (nParam)
1583 case 0:
1584 nId = NS_ooxml::LN_Value_ST_TextEffect_none;
1585 break;
1586 case 2:
1587 nId = NS_ooxml::LN_Value_ST_TextEffect_blinkBackground;
1588 break;
1591 if (nId > 0)
1592 m_aStates.top().aCharacterSprms.set(NS_ooxml::LN_EG_RPrBase_effect,
1593 new RTFValue(nId));
1594 break;
1596 case RTF_VIEWBKSP:
1598 m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_displayBackgroundShape, pIntValue);
1599 // Send this token immediately, if it only appears before the first
1600 // run, it will be too late, we ignored the background shape already by then.
1601 outputSettingsTable();
1602 break;
1604 default:
1606 SAL_INFO("writerfilter", "TODO handle value '" << keywordToString(nKeyword) << "'");
1607 aSkip.setParsed(false);
1609 break;
1611 return RTFError::OK;
1614 } // namespace rtftok
1615 } // namespace writerfilter
1617 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */