File: | home/maarten/src/libreoffice/core/include/tools/ref.hxx |
Warning: | line 87, column 19 Potential memory leak |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ | |||
2 | /* | |||
3 | * This file is part of the LibreOffice project. | |||
4 | * | |||
5 | * This Source Code Form is subject to the terms of the Mozilla Public | |||
6 | * License, v. 2.0. If a copy of the MPL was not distributed with this | |||
7 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. | |||
8 | */ | |||
9 | ||||
10 | #include "rtfdocumentimpl.hxx" | |||
11 | ||||
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/UnitConversion.hxx> | |||
21 | ||||
22 | #include <ooxml/resourceids.hxx> | |||
23 | ||||
24 | #include "rtfcharsets.hxx" | |||
25 | #include "rtffly.hxx" | |||
26 | #include "rtfreferenceproperties.hxx" | |||
27 | #include "rtfskipdestination.hxx" | |||
28 | ||||
29 | #include <unotools/defaultencoding.hxx> | |||
30 | #include <unotools/wincodepage.hxx> | |||
31 | ||||
32 | using namespace com::sun::star; | |||
33 | ||||
34 | namespace writerfilter | |||
35 | { | |||
36 | static int getNumberFormat(int nParam) | |||
37 | { | |||
38 | static const int aMap[] | |||
39 | = { NS_ooxml::LN_Value_ST_NumberFormat_decimal, | |||
40 | NS_ooxml::LN_Value_ST_NumberFormat_upperRoman, | |||
41 | NS_ooxml::LN_Value_ST_NumberFormat_lowerRoman, | |||
42 | NS_ooxml::LN_Value_ST_NumberFormat_upperLetter, | |||
43 | NS_ooxml::LN_Value_ST_NumberFormat_lowerLetter, | |||
44 | NS_ooxml::LN_Value_ST_NumberFormat_ordinal, | |||
45 | NS_ooxml::LN_Value_ST_NumberFormat_cardinalText, | |||
46 | NS_ooxml::LN_Value_ST_NumberFormat_ordinalText, | |||
47 | NS_ooxml::LN_Value_ST_NumberFormat_none, // Undefined in RTF 1.8 spec. | |||
48 | NS_ooxml::LN_Value_ST_NumberFormat_none, // Undefined in RTF 1.8 spec. | |||
49 | NS_ooxml::LN_Value_ST_NumberFormat_ideographDigital, | |||
50 | NS_ooxml::LN_Value_ST_NumberFormat_japaneseCounting, | |||
51 | NS_ooxml::LN_Value_ST_NumberFormat_aiueo, | |||
52 | NS_ooxml::LN_Value_ST_NumberFormat_iroha, | |||
53 | NS_ooxml::LN_Value_ST_NumberFormat_decimalFullWidth, | |||
54 | NS_ooxml::LN_Value_ST_NumberFormat_decimalHalfWidth, | |||
55 | NS_ooxml::LN_Value_ST_NumberFormat_japaneseLegal, | |||
56 | NS_ooxml::LN_Value_ST_NumberFormat_japaneseDigitalTenThousand, | |||
57 | NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedCircleChinese, | |||
58 | NS_ooxml::LN_Value_ST_NumberFormat_decimalFullWidth2, | |||
59 | NS_ooxml::LN_Value_ST_NumberFormat_aiueoFullWidth, | |||
60 | NS_ooxml::LN_Value_ST_NumberFormat_irohaFullWidth, | |||
61 | NS_ooxml::LN_Value_ST_NumberFormat_decimalZero, | |||
62 | NS_ooxml::LN_Value_ST_NumberFormat_bullet, | |||
63 | NS_ooxml::LN_Value_ST_NumberFormat_ganada, | |||
64 | NS_ooxml::LN_Value_ST_NumberFormat_chosung, | |||
65 | NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedFullstop, | |||
66 | NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedParen, | |||
67 | NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedCircleChinese, | |||
68 | NS_ooxml::LN_Value_ST_NumberFormat_ideographEnclosedCircle, | |||
69 | NS_ooxml::LN_Value_ST_NumberFormat_ideographTraditional, | |||
70 | NS_ooxml::LN_Value_ST_NumberFormat_ideographZodiac, | |||
71 | NS_ooxml::LN_Value_ST_NumberFormat_ideographZodiacTraditional, | |||
72 | NS_ooxml::LN_Value_ST_NumberFormat_taiwaneseCounting, | |||
73 | NS_ooxml::LN_Value_ST_NumberFormat_ideographLegalTraditional, | |||
74 | NS_ooxml::LN_Value_ST_NumberFormat_taiwaneseCountingThousand, | |||
75 | NS_ooxml::LN_Value_ST_NumberFormat_taiwaneseDigital, | |||
76 | NS_ooxml::LN_Value_ST_NumberFormat_chineseCounting, | |||
77 | NS_ooxml::LN_Value_ST_NumberFormat_chineseLegalSimplified, | |||
78 | NS_ooxml::LN_Value_ST_NumberFormat_chineseCountingThousand, | |||
79 | NS_ooxml::LN_Value_ST_NumberFormat_decimal, | |||
80 | NS_ooxml::LN_Value_ST_NumberFormat_koreanDigital, | |||
81 | NS_ooxml::LN_Value_ST_NumberFormat_koreanCounting, | |||
82 | NS_ooxml::LN_Value_ST_NumberFormat_koreanLegal, | |||
83 | NS_ooxml::LN_Value_ST_NumberFormat_koreanDigital2, | |||
84 | NS_ooxml::LN_Value_ST_NumberFormat_hebrew1, | |||
85 | NS_ooxml::LN_Value_ST_NumberFormat_arabicAlpha, | |||
86 | NS_ooxml::LN_Value_ST_NumberFormat_hebrew2, | |||
87 | NS_ooxml::LN_Value_ST_NumberFormat_arabicAbjad }; | |||
88 | const int nLen = SAL_N_ELEMENTS(aMap)(sizeof(sal_n_array_size(aMap))); | |||
89 | int nValue = 0; | |||
90 | if (nParam >= 0 && nParam < nLen) | |||
91 | nValue = aMap[nParam]; | |||
92 | else // 255 and the other cases. | |||
93 | nValue = NS_ooxml::LN_Value_ST_NumberFormat_none; | |||
94 | return nValue; | |||
95 | } | |||
96 | ||||
97 | namespace rtftok | |||
98 | { | |||
99 | bool RTFDocumentImpl::dispatchTableSprmValue(RTFKeyword nKeyword, int nParam) | |||
100 | { | |||
101 | int nSprm = 0; | |||
102 | tools::SvRef<RTFValue> pIntValue(new RTFValue(nParam)); | |||
103 | switch (nKeyword) | |||
104 | { | |||
105 | case RTF_LEVELJC: | |||
106 | { | |||
107 | nSprm = NS_ooxml::LN_CT_Lvl_lvlJc; | |||
108 | int nValue = 0; | |||
109 | switch (nParam) | |||
110 | { | |||
111 | case 0: | |||
112 | nValue = NS_ooxml::LN_Value_ST_Jc_left; | |||
113 | break; | |||
114 | case 1: | |||
115 | nValue = NS_ooxml::LN_Value_ST_Jc_center; | |||
116 | break; | |||
117 | case 2: | |||
118 | nValue = NS_ooxml::LN_Value_ST_Jc_right; | |||
119 | break; | |||
120 | } | |||
121 | pIntValue = new RTFValue(nValue); | |||
122 | break; | |||
123 | } | |||
124 | case RTF_LEVELSTARTAT: | |||
125 | nSprm = NS_ooxml::LN_CT_Lvl_start; | |||
126 | break; | |||
127 | case RTF_LEVELPICTURE: | |||
128 | nSprm = NS_ooxml::LN_CT_Lvl_lvlPicBulletId; | |||
129 | break; | |||
130 | case RTF_SBASEDON: | |||
131 | nSprm = NS_ooxml::LN_CT_Style_basedOn; | |||
132 | pIntValue = new RTFValue(getStyleName(nParam)); | |||
133 | break; | |||
134 | default: | |||
135 | break; | |||
136 | } | |||
137 | if (nSprm > 0) | |||
138 | { | |||
139 | m_aStates.top().getTableSprms().set(nSprm, pIntValue); | |||
140 | return true; | |||
141 | } | |||
142 | if (nKeyword == RTF_LEVELNFC) | |||
143 | { | |||
144 | pIntValue = new RTFValue(getNumberFormat(nParam)); | |||
145 | putNestedAttribute(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_Lvl_numFmt, | |||
146 | NS_ooxml::LN_CT_NumFmt_val, pIntValue); | |||
147 | return true; | |||
148 | } | |||
149 | ||||
150 | return false; | |||
151 | } | |||
152 | ||||
153 | bool RTFDocumentImpl::dispatchCharacterSprmValue(RTFKeyword nKeyword, int nParam) | |||
154 | { | |||
155 | int nSprm = 0; | |||
156 | tools::SvRef<RTFValue> pIntValue(new RTFValue(nParam)); | |||
157 | ||||
158 | switch (nKeyword) | |||
159 | { | |||
160 | case RTF_FS: | |||
161 | case RTF_AFS: | |||
162 | switch (m_aStates.top().getRunType()) | |||
163 | { | |||
164 | case RTFParserState::RunType::HICH: | |||
165 | case RTFParserState::RunType::RTLCH_LTRCH_1: | |||
166 | case RTFParserState::RunType::LTRCH_RTLCH_2: | |||
167 | case RTFParserState::RunType::DBCH: | |||
168 | nSprm = NS_ooxml::LN_EG_RPrBase_szCs; | |||
169 | break; | |||
170 | case RTFParserState::RunType::NONE: | |||
171 | case RTFParserState::RunType::LOCH: | |||
172 | case RTFParserState::RunType::LTRCH_RTLCH_1: | |||
173 | case RTFParserState::RunType::RTLCH_LTRCH_2: | |||
174 | default: | |||
175 | nSprm = NS_ooxml::LN_EG_RPrBase_sz; | |||
176 | break; | |||
177 | } | |||
178 | break; | |||
179 | case RTF_EXPNDTW: | |||
180 | nSprm = NS_ooxml::LN_EG_RPrBase_spacing; | |||
181 | break; | |||
182 | case RTF_KERNING: | |||
183 | nSprm = NS_ooxml::LN_EG_RPrBase_kern; | |||
184 | break; | |||
185 | case RTF_CHARSCALEX: | |||
186 | nSprm = NS_ooxml::LN_EG_RPrBase_w; | |||
187 | break; | |||
188 | default: | |||
189 | break; | |||
190 | } | |||
191 | if (nSprm > 0) | |||
192 | { | |||
193 | m_aStates.top().getCharacterSprms().set(nSprm, pIntValue); | |||
194 | return true; | |||
195 | } | |||
196 | ||||
197 | return false; | |||
198 | } | |||
199 | ||||
200 | bool RTFDocumentImpl::dispatchCharacterAttributeValue(RTFKeyword nKeyword, int nParam) | |||
201 | { | |||
202 | int nSprm = 0; | |||
203 | ||||
204 | switch (nKeyword) | |||
205 | { | |||
206 | case RTF_LANG: | |||
207 | case RTF_ALANG: | |||
208 | switch (m_aStates.top().getRunType()) | |||
209 | { | |||
210 | case RTFParserState::RunType::HICH: | |||
211 | case RTFParserState::RunType::RTLCH_LTRCH_1: | |||
212 | case RTFParserState::RunType::LTRCH_RTLCH_2: | |||
213 | nSprm = NS_ooxml::LN_CT_Language_bidi; | |||
214 | break; | |||
215 | case RTFParserState::RunType::DBCH: | |||
216 | nSprm = NS_ooxml::LN_CT_Language_eastAsia; | |||
217 | break; | |||
218 | case RTFParserState::RunType::NONE: | |||
219 | case RTFParserState::RunType::LOCH: | |||
220 | case RTFParserState::RunType::LTRCH_RTLCH_1: | |||
221 | case RTFParserState::RunType::RTLCH_LTRCH_2: | |||
222 | default: | |||
223 | nSprm = NS_ooxml::LN_CT_Language_val; | |||
224 | break; | |||
225 | } | |||
226 | break; | |||
227 | case RTF_LANGFE: // this one is always CJK apparently | |||
228 | nSprm = NS_ooxml::LN_CT_Language_eastAsia; | |||
229 | break; | |||
230 | default: | |||
231 | break; | |||
232 | } | |||
233 | if (nSprm > 0) | |||
234 | { | |||
235 | LanguageTag aTag((LanguageType(static_cast<sal_uInt16>(nParam)))); | |||
236 | auto pValue = new RTFValue(aTag.getBcp47()); | |||
237 | putNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_lang, nSprm, | |||
238 | pValue); | |||
239 | // Language is a character property, but we should store it at a paragraph level as well for fields. | |||
240 | if (nKeyword == RTF_LANG && m_bNeedPap) | |||
241 | putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_EG_RPrBase_lang, | |||
242 | nSprm, pValue); | |||
243 | return true; | |||
244 | } | |||
245 | ||||
246 | return false; | |||
247 | } | |||
248 | ||||
249 | bool RTFDocumentImpl::dispatchParagraphSprmValue(RTFKeyword nKeyword, int nParam) | |||
250 | { | |||
251 | int nSprm = 0; | |||
252 | tools::SvRef<RTFValue> pIntValue(new RTFValue(nParam)); | |||
253 | ||||
254 | switch (nKeyword) | |||
255 | { | |||
256 | case RTF_ITAP: | |||
257 | nSprm = NS_ooxml::LN_tblDepth; | |||
258 | // tdf#117268: If \itap0 is encountered inside tables (between \cellxN and \cell), then | |||
259 | // use the default value (1), as Word apparently does | |||
260 | if (nParam == 0 && (m_nTopLevelCells != 0 || m_nNestedCells != 0)) | |||
261 | { | |||
262 | nParam = 1; | |||
263 | pIntValue = new RTFValue(nParam); | |||
264 | } | |||
265 | break; | |||
266 | default: | |||
267 | break; | |||
268 | } | |||
269 | if (nSprm > 0) | |||
270 | { | |||
271 | m_aStates.top().getParagraphSprms().set(nSprm, pIntValue); | |||
272 | if (nKeyword == RTF_ITAP && nParam > 0) | |||
273 | { | |||
274 | while (m_aTableBufferStack.size() < sal::static_int_cast<std::size_t>(nParam)) | |||
275 | { | |||
276 | m_aTableBufferStack.emplace_back(RTFBuffer_t()); | |||
277 | } | |||
278 | // Invalid tables may omit INTBL after ITAP | |||
279 | dispatchFlag(RTF_INTBL); // sets newly pushed buffer as current | |||
280 | assert(m_aStates.top().getCurrentBuffer() == &m_aTableBufferStack.back())(static_cast <bool> (m_aStates.top().getCurrentBuffer() == &m_aTableBufferStack.back()) ? void (0) : __assert_fail ("m_aStates.top().getCurrentBuffer() == &m_aTableBufferStack.back()" , "/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdispatchvalue.cxx" , 280, __extension__ __PRETTY_FUNCTION__)); | |||
281 | } | |||
282 | return true; | |||
283 | } | |||
284 | ||||
285 | return false; | |||
286 | } | |||
287 | ||||
288 | bool RTFDocumentImpl::dispatchInfoValue(RTFKeyword nKeyword, int nParam) | |||
289 | { | |||
290 | int nSprm = 0; | |||
291 | ||||
292 | switch (nKeyword) | |||
293 | { | |||
294 | case RTF_YR: | |||
295 | { | |||
296 | m_aStates.top().setYear(nParam); | |||
297 | nSprm = 1; | |||
298 | } | |||
299 | break; | |||
300 | case RTF_MO: | |||
301 | { | |||
302 | m_aStates.top().setMonth(nParam); | |||
303 | nSprm = 1; | |||
304 | } | |||
305 | break; | |||
306 | case RTF_DY: | |||
307 | { | |||
308 | m_aStates.top().setDay(nParam); | |||
309 | nSprm = 1; | |||
310 | } | |||
311 | break; | |||
312 | case RTF_HR: | |||
313 | { | |||
314 | m_aStates.top().setHour(nParam); | |||
315 | nSprm = 1; | |||
316 | } | |||
317 | break; | |||
318 | case RTF_MIN: | |||
319 | { | |||
320 | m_aStates.top().setMinute(nParam); | |||
321 | nSprm = 1; | |||
322 | } | |||
323 | break; | |||
324 | default: | |||
325 | break; | |||
326 | } | |||
327 | ||||
328 | return nSprm > 0; | |||
329 | } | |||
330 | ||||
331 | bool RTFDocumentImpl::dispatchFrameValue(RTFKeyword nKeyword, int nParam) | |||
332 | { | |||
333 | Id nId = 0; | |||
334 | switch (nKeyword) | |||
335 | { | |||
336 | case RTF_ABSW: | |||
337 | nId = NS_ooxml::LN_CT_FramePr_w; | |||
338 | break; | |||
339 | case RTF_ABSH: | |||
340 | nId = NS_ooxml::LN_CT_FramePr_h; | |||
341 | break; | |||
342 | case RTF_POSX: | |||
343 | { | |||
344 | nId = NS_ooxml::LN_CT_FramePr_x; | |||
345 | m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_xAlign, 0); | |||
346 | } | |||
347 | break; | |||
348 | case RTF_POSY: | |||
349 | { | |||
350 | nId = NS_ooxml::LN_CT_FramePr_y; | |||
351 | m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign, 0); | |||
352 | } | |||
353 | break; | |||
354 | default: | |||
355 | break; | |||
356 | } | |||
357 | ||||
358 | if (nId > 0) | |||
359 | { | |||
360 | m_bNeedPap = true; | |||
361 | // Don't try to support text frames inside tables for now. | |||
362 | if (m_aStates.top().getCurrentBuffer() != &m_aTableBufferStack.back()) | |||
363 | m_aStates.top().getFrame().setSprm(nId, nParam); | |||
364 | ||||
365 | return true; | |||
366 | } | |||
367 | ||||
368 | return false; | |||
369 | } | |||
370 | ||||
371 | bool RTFDocumentImpl::dispatchTableValue(RTFKeyword nKeyword, int nParam) | |||
372 | { | |||
373 | int nSprm = 0; | |||
374 | tools::SvRef<RTFValue> pIntValue(new RTFValue(nParam)); | |||
375 | ||||
376 | switch (nKeyword) | |||
377 | { | |||
378 | case RTF_CELLX: | |||
379 | { | |||
380 | int& rCurrentCellX( | |||
381 | (Destination::NESTEDTABLEPROPERTIES == m_aStates.top().getDestination()) | |||
382 | ? m_nNestedCurrentCellX | |||
383 | : m_nTopLevelCurrentCellX); | |||
384 | int nCellX = nParam - rCurrentCellX; | |||
385 | const int COL_DFLT_WIDTH | |||
386 | = 41; // sw/source/filter/inc/wrtswtbl.hxx, minimal possible width of cells. | |||
387 | if (!nCellX) | |||
388 | nCellX = COL_DFLT_WIDTH; | |||
389 | ||||
390 | // If there is a negative left margin, then the first cellx is relative to that. | |||
391 | RTFValue::Pointer_t pTblInd | |||
392 | = m_aStates.top().getTableRowSprms().find(NS_ooxml::LN_CT_TblPrBase_tblInd); | |||
393 | if (rCurrentCellX == 0 && pTblInd) | |||
394 | { | |||
395 | RTFValue::Pointer_t pWidth | |||
396 | = pTblInd->getAttributes().find(NS_ooxml::LN_CT_TblWidth_w); | |||
397 | if (pWidth && pWidth->getInt() < 0) | |||
398 | nCellX = -1 * (pWidth->getInt() - nParam); | |||
399 | } | |||
400 | ||||
401 | rCurrentCellX = nParam; | |||
402 | auto pXValue = new RTFValue(nCellX); | |||
403 | m_aStates.top().getTableRowSprms().set(NS_ooxml::LN_CT_TblGridBase_gridCol, pXValue, | |||
404 | RTFOverwrite::NO_APPEND); | |||
405 | if (Destination::NESTEDTABLEPROPERTIES == m_aStates.top().getDestination()) | |||
406 | { | |||
407 | m_nNestedCells++; | |||
408 | // Push cell properties. | |||
409 | m_aNestedTableCellsSprms.push_back(m_aStates.top().getTableCellSprms()); | |||
410 | m_aNestedTableCellsAttributes.push_back(m_aStates.top().getTableCellAttributes()); | |||
411 | } | |||
412 | else | |||
413 | { | |||
414 | m_nTopLevelCells++; | |||
415 | // Push cell properties. | |||
416 | m_aTopLevelTableCellsSprms.push_back(m_aStates.top().getTableCellSprms()); | |||
417 | m_aTopLevelTableCellsAttributes.push_back(m_aStates.top().getTableCellAttributes()); | |||
418 | } | |||
419 | ||||
420 | m_aStates.top().getTableCellSprms() = m_aDefaultState.getTableCellSprms(); | |||
421 | m_aStates.top().getTableCellAttributes() = m_aDefaultState.getTableCellAttributes(); | |||
422 | // We assume text after a row definition always belongs to the table, to handle text before the real INTBL token | |||
423 | dispatchFlag(RTF_INTBL); | |||
424 | if (!m_nCellxMax) | |||
425 | { | |||
426 | // Wasn't in table, but now is -> tblStart. | |||
427 | RTFSprms aAttributes; | |||
428 | RTFSprms aSprms; | |||
429 | aSprms.set(NS_ooxml::LN_tblStart, new RTFValue(1)); | |||
430 | writerfilter::Reference<Properties>::Pointer_t pProperties | |||
431 | = new RTFReferenceProperties(aAttributes, aSprms); | |||
432 | Mapper().props(pProperties); | |||
433 | } | |||
434 | m_nCellxMax = std::max(m_nCellxMax, nParam); | |||
435 | return true; | |||
436 | } | |||
437 | break; | |||
438 | case RTF_TRRH: | |||
439 | { | |||
440 | OUString hRule("auto"); | |||
441 | if (nParam < 0) | |||
442 | { | |||
443 | tools::SvRef<RTFValue> pAbsValue(new RTFValue(-nParam)); | |||
444 | std::swap(pIntValue, pAbsValue); | |||
445 | ||||
446 | hRule = "exact"; | |||
447 | } | |||
448 | else if (nParam > 0) | |||
449 | hRule = "atLeast"; | |||
450 | ||||
451 | putNestedAttribute(m_aStates.top().getTableRowSprms(), | |||
452 | NS_ooxml::LN_CT_TrPrBase_trHeight, NS_ooxml::LN_CT_Height_val, | |||
453 | pIntValue); | |||
454 | ||||
455 | auto pHRule = new RTFValue(hRule); | |||
456 | putNestedAttribute(m_aStates.top().getTableRowSprms(), | |||
457 | NS_ooxml::LN_CT_TrPrBase_trHeight, NS_ooxml::LN_CT_Height_hRule, | |||
458 | pHRule); | |||
459 | return true; | |||
460 | } | |||
461 | break; | |||
462 | case RTF_TRLEFT: | |||
463 | { | |||
464 | // the value is in twips | |||
465 | putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblInd, | |||
466 | NS_ooxml::LN_CT_TblWidth_type, | |||
467 | new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa)); | |||
468 | putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblInd, | |||
469 | NS_ooxml::LN_CT_TblWidth_w, new RTFValue(nParam)); | |||
470 | auto const aDestination = m_aStates.top().getDestination(); | |||
471 | int& rCurrentTRLeft((Destination::NESTEDTABLEPROPERTIES == aDestination) | |||
472 | ? m_nNestedTRLeft | |||
473 | : m_nTopLevelTRLeft); | |||
474 | int& rCurrentCellX((Destination::NESTEDTABLEPROPERTIES == aDestination) | |||
475 | ? m_nNestedCurrentCellX | |||
476 | : m_nTopLevelCurrentCellX); | |||
477 | rCurrentTRLeft = rCurrentCellX = nParam; | |||
478 | return true; | |||
479 | } | |||
480 | break; | |||
481 | case RTF_CLSHDNG: | |||
482 | { | |||
483 | int nValue = -1; | |||
484 | switch (nParam) | |||
485 | { | |||
486 | case 500: | |||
487 | nValue = NS_ooxml::LN_Value_ST_Shd_pct5; | |||
488 | break; | |||
489 | case 1000: | |||
490 | nValue = NS_ooxml::LN_Value_ST_Shd_pct10; | |||
491 | break; | |||
492 | case 1200: | |||
493 | nValue = NS_ooxml::LN_Value_ST_Shd_pct12; | |||
494 | break; | |||
495 | case 1500: | |||
496 | nValue = NS_ooxml::LN_Value_ST_Shd_pct15; | |||
497 | break; | |||
498 | case 2000: | |||
499 | nValue = NS_ooxml::LN_Value_ST_Shd_pct20; | |||
500 | break; | |||
501 | case 2500: | |||
502 | nValue = NS_ooxml::LN_Value_ST_Shd_pct25; | |||
503 | break; | |||
504 | case 3000: | |||
505 | nValue = NS_ooxml::LN_Value_ST_Shd_pct30; | |||
506 | break; | |||
507 | case 3500: | |||
508 | nValue = NS_ooxml::LN_Value_ST_Shd_pct35; | |||
509 | break; | |||
510 | case 3700: | |||
511 | nValue = NS_ooxml::LN_Value_ST_Shd_pct37; | |||
512 | break; | |||
513 | case 4000: | |||
514 | nValue = NS_ooxml::LN_Value_ST_Shd_pct40; | |||
515 | break; | |||
516 | case 4500: | |||
517 | nValue = NS_ooxml::LN_Value_ST_Shd_pct45; | |||
518 | break; | |||
519 | case 5000: | |||
520 | nValue = NS_ooxml::LN_Value_ST_Shd_pct50; | |||
521 | break; | |||
522 | case 5500: | |||
523 | nValue = NS_ooxml::LN_Value_ST_Shd_pct55; | |||
524 | break; | |||
525 | case 6000: | |||
526 | nValue = NS_ooxml::LN_Value_ST_Shd_pct60; | |||
527 | break; | |||
528 | case 6200: | |||
529 | nValue = NS_ooxml::LN_Value_ST_Shd_pct62; | |||
530 | break; | |||
531 | case 6500: | |||
532 | nValue = NS_ooxml::LN_Value_ST_Shd_pct65; | |||
533 | break; | |||
534 | case 7000: | |||
535 | nValue = NS_ooxml::LN_Value_ST_Shd_pct70; | |||
536 | break; | |||
537 | case 7500: | |||
538 | nValue = NS_ooxml::LN_Value_ST_Shd_pct75; | |||
539 | break; | |||
540 | case 8000: | |||
541 | nValue = NS_ooxml::LN_Value_ST_Shd_pct80; | |||
542 | break; | |||
543 | case 8500: | |||
544 | nValue = NS_ooxml::LN_Value_ST_Shd_pct85; | |||
545 | break; | |||
546 | case 8700: | |||
547 | nValue = NS_ooxml::LN_Value_ST_Shd_pct87; | |||
548 | break; | |||
549 | case 9000: | |||
550 | nValue = NS_ooxml::LN_Value_ST_Shd_pct90; | |||
551 | break; | |||
552 | case 9500: | |||
553 | nValue = NS_ooxml::LN_Value_ST_Shd_pct95; | |||
554 | break; | |||
555 | default: | |||
556 | break; | |||
557 | } | |||
558 | if (nValue != -1) | |||
559 | putNestedAttribute(m_aStates.top().getTableCellSprms(), | |||
560 | NS_ooxml::LN_CT_TcPrBase_shd, NS_ooxml::LN_CT_Shd_val, | |||
561 | new RTFValue(nValue)); | |||
562 | return true; | |||
563 | } | |||
564 | break; | |||
565 | case RTF_CLPADB: | |||
566 | case RTF_CLPADL: | |||
567 | case RTF_CLPADR: | |||
568 | case RTF_CLPADT: | |||
569 | { | |||
570 | RTFSprms aAttributes; | |||
571 | aAttributes.set(NS_ooxml::LN_CT_TblWidth_type, | |||
572 | new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa)); | |||
573 | aAttributes.set(NS_ooxml::LN_CT_TblWidth_w, new RTFValue(nParam)); | |||
574 | // Top and left is swapped, that's what Word does. | |||
575 | switch (nKeyword) | |||
576 | { | |||
577 | case RTF_CLPADB: | |||
578 | nSprm = NS_ooxml::LN_CT_TcMar_bottom; | |||
579 | break; | |||
580 | case RTF_CLPADL: | |||
581 | nSprm = NS_ooxml::LN_CT_TcMar_top; | |||
582 | break; | |||
583 | case RTF_CLPADR: | |||
584 | nSprm = NS_ooxml::LN_CT_TcMar_right; | |||
585 | break; | |||
586 | case RTF_CLPADT: | |||
587 | nSprm = NS_ooxml::LN_CT_TcMar_left; | |||
588 | break; | |||
589 | default: | |||
590 | break; | |||
591 | } | |||
592 | putNestedSprm(m_aStates.top().getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcMar, | |||
593 | nSprm, new RTFValue(aAttributes)); | |||
594 | return true; | |||
595 | } | |||
596 | break; | |||
597 | case RTF_TRPADDFB: | |||
598 | case RTF_TRPADDFL: | |||
599 | case RTF_TRPADDFR: | |||
600 | case RTF_TRPADDFT: | |||
601 | { | |||
602 | RTFSprms aAttributes; | |||
603 | switch (nParam) | |||
604 | { | |||
605 | case 3: | |||
606 | aAttributes.set(NS_ooxml::LN_CT_TblWidth_type, | |||
607 | new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa)); | |||
608 | break; | |||
609 | } | |||
610 | switch (nKeyword) | |||
611 | { | |||
612 | case RTF_TRPADDFB: | |||
613 | nSprm = NS_ooxml::LN_CT_TcMar_bottom; | |||
614 | break; | |||
615 | case RTF_TRPADDFL: | |||
616 | nSprm = NS_ooxml::LN_CT_TcMar_left; | |||
617 | break; | |||
618 | case RTF_TRPADDFR: | |||
619 | nSprm = NS_ooxml::LN_CT_TcMar_right; | |||
620 | break; | |||
621 | case RTF_TRPADDFT: | |||
622 | nSprm = NS_ooxml::LN_CT_TcMar_top; | |||
623 | break; | |||
624 | default: | |||
625 | break; | |||
626 | } | |||
627 | putNestedAttribute(m_aStates.top().getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcMar, | |||
628 | nSprm, new RTFValue(aAttributes)); | |||
629 | putNestedAttribute(m_aDefaultState.getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcMar, | |||
630 | nSprm, new RTFValue(aAttributes)); | |||
631 | return true; | |||
632 | } | |||
633 | break; | |||
634 | case RTF_TRPADDB: | |||
635 | case RTF_TRPADDL: | |||
636 | case RTF_TRPADDR: | |||
637 | case RTF_TRPADDT: | |||
638 | { | |||
639 | RTFSprms aAttributes; | |||
640 | aAttributes.set(NS_ooxml::LN_CT_TblWidth_w, new RTFValue(nParam)); | |||
641 | switch (nKeyword) | |||
642 | { | |||
643 | case RTF_TRPADDB: | |||
644 | nSprm = NS_ooxml::LN_CT_TcMar_bottom; | |||
645 | break; | |||
646 | case RTF_TRPADDL: | |||
647 | nSprm = NS_ooxml::LN_CT_TcMar_left; | |||
648 | break; | |||
649 | case RTF_TRPADDR: | |||
650 | nSprm = NS_ooxml::LN_CT_TcMar_right; | |||
651 | break; | |||
652 | case RTF_TRPADDT: | |||
653 | nSprm = NS_ooxml::LN_CT_TcMar_top; | |||
654 | break; | |||
655 | default: | |||
656 | break; | |||
657 | } | |||
658 | putNestedSprm(m_aStates.top().getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcMar, | |||
659 | nSprm, new RTFValue(aAttributes)); | |||
660 | putNestedSprm(m_aDefaultState.getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcMar, | |||
661 | nSprm, new RTFValue(aAttributes)); | |||
662 | return true; | |||
663 | } | |||
664 | break; | |||
665 | case RTF_TRGAPH: | |||
666 | // Half of the space between the cells of a table row: default left/right table cell margin. | |||
667 | if (nParam > 0) | |||
668 | { | |||
669 | RTFSprms aAttributes; | |||
670 | aAttributes.set(NS_ooxml::LN_CT_TblWidth_type, | |||
671 | new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa)); | |||
672 | aAttributes.set(NS_ooxml::LN_CT_TblWidth_w, pIntValue); | |||
673 | putNestedSprm(m_aStates.top().getTableRowSprms(), | |||
674 | NS_ooxml::LN_CT_TblPrBase_tblCellMar, NS_ooxml::LN_CT_TblCellMar_left, | |||
675 | new RTFValue(aAttributes)); | |||
676 | putNestedSprm(m_aStates.top().getTableRowSprms(), | |||
677 | NS_ooxml::LN_CT_TblPrBase_tblCellMar, | |||
678 | NS_ooxml::LN_CT_TblCellMar_right, new RTFValue(aAttributes)); | |||
679 | } | |||
680 | return true; | |||
681 | break; | |||
682 | case RTF_TRFTSWIDTH: | |||
683 | putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblW, | |||
684 | NS_ooxml::LN_CT_TblWidth_type, pIntValue); | |||
685 | return true; | |||
686 | break; | |||
687 | case RTF_TRWWIDTH: | |||
688 | putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblW, | |||
689 | NS_ooxml::LN_CT_TblWidth_w, pIntValue); | |||
690 | return true; | |||
691 | break; | |||
692 | default: | |||
693 | break; | |||
694 | } | |||
695 | ||||
696 | return false; | |||
697 | } | |||
698 | ||||
699 | RTFError RTFDocumentImpl::dispatchValue(RTFKeyword nKeyword, int nParam) | |||
700 | { | |||
701 | setNeedSect(true); | |||
702 | checkUnicode(/*bUnicode =*/nKeyword != RTF_U, /*bHex =*/true); | |||
| ||||
703 | RTFSkipDestination aSkip(*this); | |||
704 | int nSprm = 0; | |||
705 | tools::SvRef<RTFValue> pIntValue(new RTFValue(nParam)); | |||
706 | // Trivial table sprms. | |||
707 | if (dispatchTableSprmValue(nKeyword, nParam)) | |||
708 | { | |||
709 | return RTFError::OK; | |||
710 | } | |||
711 | ||||
712 | // Trivial character sprms. | |||
713 | if (dispatchCharacterSprmValue(nKeyword, nParam)) | |||
714 | { | |||
715 | return RTFError::OK; | |||
716 | } | |||
717 | ||||
718 | // Trivial character attributes. | |||
719 | if (dispatchCharacterAttributeValue(nKeyword, nParam)) | |||
720 | { | |||
721 | return RTFError::OK; | |||
722 | } | |||
723 | ||||
724 | // Trivial paragraph sprms. | |||
725 | if (dispatchParagraphSprmValue(nKeyword, nParam)) | |||
726 | { | |||
727 | return RTFError::OK; | |||
728 | } | |||
729 | ||||
730 | // Info group. | |||
731 | if (dispatchInfoValue(nKeyword, nParam)) | |||
732 | { | |||
733 | return RTFError::OK; | |||
734 | } | |||
735 | ||||
736 | // Frame size / position. | |||
737 | if (dispatchFrameValue(nKeyword, nParam)) | |||
738 | { | |||
739 | return RTFError::OK; | |||
740 | } | |||
741 | ||||
742 | // Table-related values. | |||
743 | if (dispatchTableValue(nKeyword, nParam)) | |||
744 | { | |||
745 | return RTFError::OK; | |||
746 | } | |||
747 | ||||
748 | // Then check for the more complex ones. | |||
749 | switch (nKeyword) | |||
750 | { | |||
751 | case RTF_F: | |||
752 | case RTF_AF: | |||
753 | switch (m_aStates.top().getRunType()) | |||
754 | { | |||
755 | case RTFParserState::RunType::HICH: | |||
756 | case RTFParserState::RunType::RTLCH_LTRCH_1: | |||
757 | case RTFParserState::RunType::LTRCH_RTLCH_2: | |||
758 | nSprm = NS_ooxml::LN_CT_Fonts_cs; | |||
759 | break; | |||
760 | case RTFParserState::RunType::DBCH: | |||
761 | nSprm = NS_ooxml::LN_CT_Fonts_eastAsia; | |||
762 | break; | |||
763 | case RTFParserState::RunType::NONE: | |||
764 | case RTFParserState::RunType::LOCH: | |||
765 | case RTFParserState::RunType::LTRCH_RTLCH_1: | |||
766 | case RTFParserState::RunType::RTLCH_LTRCH_2: | |||
767 | default: | |||
768 | nSprm = NS_ooxml::LN_CT_Fonts_ascii; | |||
769 | break; | |||
770 | } | |||
771 | ||||
772 | if (m_aStates.top().getDestination() == Destination::FONTTABLE | |||
773 | || m_aStates.top().getDestination() == Destination::FONTENTRY) | |||
774 | { | |||
775 | m_aFontIndexes.push_back(nParam); | |||
776 | m_nCurrentFontIndex = getFontIndex(nParam); | |||
777 | } | |||
778 | else if (m_aStates.top().getDestination() == Destination::LISTLEVEL) | |||
779 | { | |||
780 | RTFSprms aFontAttributes; | |||
781 | aFontAttributes.set(nSprm, new RTFValue(m_aFontNames[getFontIndex(nParam)])); | |||
782 | RTFSprms aRunPropsSprms; | |||
783 | aRunPropsSprms.set(NS_ooxml::LN_EG_RPrBase_rFonts, new RTFValue(aFontAttributes)); | |||
784 | m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Lvl_rPr, | |||
785 | new RTFValue(RTFSprms(), aRunPropsSprms), | |||
786 | RTFOverwrite::NO_APPEND); | |||
787 | } | |||
788 | else | |||
789 | { | |||
790 | m_nCurrentFontIndex = getFontIndex(nParam); | |||
791 | auto pValue = new RTFValue(getFontName(m_nCurrentFontIndex)); | |||
792 | putNestedAttribute(m_aStates.top().getCharacterSprms(), | |||
793 | NS_ooxml::LN_EG_RPrBase_rFonts, nSprm, pValue); | |||
794 | if (nKeyword == RTF_F) | |||
795 | m_aStates.top().setCurrentEncoding(getEncoding(m_nCurrentFontIndex)); | |||
796 | } | |||
797 | break; | |||
798 | case RTF_RED: | |||
799 | m_aStates.top().getCurrentColor().SetRed(nParam); | |||
800 | break; | |||
801 | case RTF_GREEN: | |||
802 | m_aStates.top().getCurrentColor().SetGreen(nParam); | |||
803 | break; | |||
804 | case RTF_BLUE: | |||
805 | m_aStates.top().getCurrentColor().SetBlue(nParam); | |||
806 | break; | |||
807 | case RTF_FCHARSET: | |||
808 | { | |||
809 | // we always send text to the domain mapper in OUString, so no | |||
810 | // need to send encoding info | |||
811 | int i; | |||
812 | for (i = 0; i < nRTFEncodings; i++) | |||
813 | { | |||
814 | if (aRTFEncodings[i].charset == nParam) | |||
815 | break; | |||
816 | } | |||
817 | if (i == nRTFEncodings) | |||
818 | // not found | |||
819 | return RTFError::OK; | |||
820 | ||||
821 | m_nCurrentEncoding | |||
822 | = aRTFEncodings[i].codepage == 0 // Default (CP_ACP) | |||
823 | ? osl_getThreadTextEncoding() | |||
824 | : rtl_getTextEncodingFromWindowsCodePage(aRTFEncodings[i].codepage); | |||
825 | m_aStates.top().setCurrentEncoding(m_nCurrentEncoding); | |||
826 | } | |||
827 | break; | |||
828 | case RTF_ANSICPG: | |||
829 | case RTF_CPG: | |||
830 | { | |||
831 | rtl_TextEncoding nEncoding | |||
832 | = (nParam == 0) | |||
833 | ? utl_getWinTextEncodingFromLangStr(utl_getLocaleForGlobalDefaultEncoding()) | |||
834 | : rtl_getTextEncodingFromWindowsCodePage(nParam); | |||
835 | if (nKeyword == RTF_ANSICPG) | |||
836 | m_aDefaultState.setCurrentEncoding(nEncoding); | |||
837 | else | |||
838 | m_nCurrentEncoding = nEncoding; | |||
839 | m_aStates.top().setCurrentEncoding(nEncoding); | |||
840 | } | |||
841 | break; | |||
842 | case RTF_CF: | |||
843 | { | |||
844 | RTFSprms aAttributes; | |||
845 | auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam))); | |||
846 | aAttributes.set(NS_ooxml::LN_CT_Color_val, pValue); | |||
847 | m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_color, | |||
848 | new RTFValue(aAttributes)); | |||
849 | } | |||
850 | break; | |||
851 | case RTF_S: | |||
852 | { | |||
853 | m_aStates.top().setCurrentStyleIndex(nParam); | |||
854 | ||||
855 | if (m_aStates.top().getDestination() == Destination::STYLESHEET | |||
856 | || m_aStates.top().getDestination() == Destination::STYLEENTRY) | |||
857 | { | |||
858 | m_nCurrentStyleIndex = nParam; | |||
859 | auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_StyleType_paragraph); | |||
860 | m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_type, | |||
861 | pValue); // paragraph style | |||
862 | } | |||
863 | else | |||
864 | { | |||
865 | OUString aName = getStyleName(nParam); | |||
866 | if (!aName.isEmpty()) | |||
867 | { | |||
868 | if (m_aStates.top().getDestination() == Destination::LISTLEVEL) | |||
869 | m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Lvl_pStyle, | |||
870 | new RTFValue(aName)); | |||
871 | else | |||
872 | m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_pStyle, | |||
873 | new RTFValue(aName)); | |||
874 | } | |||
875 | } | |||
876 | } | |||
877 | break; | |||
878 | case RTF_CS: | |||
879 | m_aStates.top().setCurrentCharacterStyleIndex(nParam); | |||
880 | if (m_aStates.top().getDestination() == Destination::STYLESHEET | |||
881 | || m_aStates.top().getDestination() == Destination::STYLEENTRY) | |||
882 | { | |||
883 | m_nCurrentStyleIndex = nParam; | |||
884 | auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_StyleType_character); | |||
885 | m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_type, | |||
886 | pValue); // character style | |||
887 | } | |||
888 | else | |||
889 | { | |||
890 | OUString aName = getStyleName(nParam); | |||
891 | if (!aName.isEmpty()) | |||
892 | m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_rStyle, | |||
893 | new RTFValue(aName)); | |||
894 | } | |||
895 | break; | |||
896 | case RTF_DS: | |||
897 | if (m_aStates.top().getDestination() == Destination::STYLESHEET | |||
898 | || m_aStates.top().getDestination() == Destination::STYLEENTRY) | |||
899 | { | |||
900 | m_nCurrentStyleIndex = nParam; | |||
901 | auto pValue = new RTFValue(0); // TODO no value in enum StyleType? | |||
902 | m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_type, | |||
903 | pValue); // section style | |||
904 | } | |||
905 | break; | |||
906 | case RTF_TS: | |||
907 | if (m_aStates.top().getDestination() == Destination::STYLESHEET | |||
908 | || m_aStates.top().getDestination() == Destination::STYLEENTRY) | |||
909 | { | |||
910 | m_nCurrentStyleIndex = nParam; | |||
911 | // 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 | |||
912 | auto pValue = new RTFValue(0); | |||
913 | m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_type, | |||
914 | pValue); // table style | |||
915 | } | |||
916 | break; | |||
917 | case RTF_DEFF: | |||
918 | m_nDefaultFontIndex = nParam; | |||
919 | break; | |||
920 | case RTF_STSHFDBCH: | |||
921 | // tdf#123703 switch off longer space sequence except in the case of the fixed compatibility setting font id 31505 | |||
922 | if (nParam != 31505) | |||
923 | m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_longerSpaceSequence, | |||
924 | new RTFValue(0)); | |||
925 | break; | |||
926 | case RTF_DEFLANG: | |||
927 | case RTF_ADEFLANG: | |||
928 | { | |||
929 | LanguageTag aTag((LanguageType(static_cast<sal_uInt16>(nParam)))); | |||
930 | auto pValue = new RTFValue(aTag.getBcp47()); | |||
931 | putNestedAttribute(m_aStates.top().getCharacterSprms(), | |||
932 | (nKeyword == RTF_DEFLANG ? NS_ooxml::LN_EG_RPrBase_lang | |||
933 | : NS_ooxml::LN_CT_Language_bidi), | |||
934 | nSprm, pValue); | |||
935 | } | |||
936 | break; | |||
937 | case RTF_CHCBPAT: | |||
938 | { | |||
939 | auto pValue = new RTFValue(sal_uInt32(nParam ? getColorTable(nParam) : COL_AUTO)); | |||
940 | putNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_shd, | |||
941 | NS_ooxml::LN_CT_Shd_fill, pValue); | |||
942 | } | |||
943 | break; | |||
944 | case RTF_CLCBPAT: | |||
945 | case RTF_CLCBPATRAW: | |||
946 | { | |||
947 | auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam))); | |||
948 | putNestedAttribute(m_aStates.top().getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_shd, | |||
949 | NS_ooxml::LN_CT_Shd_fill, pValue); | |||
950 | } | |||
951 | break; | |||
952 | case RTF_CBPAT: | |||
953 | if (nParam) | |||
954 | { | |||
955 | auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam))); | |||
956 | putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PrBase_shd, | |||
957 | NS_ooxml::LN_CT_Shd_fill, pValue); | |||
958 | } | |||
959 | break; | |||
960 | case RTF_ULC: | |||
961 | { | |||
962 | auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam))); | |||
963 | m_aStates.top().getCharacterSprms().set(0x6877, pValue); | |||
964 | } | |||
965 | break; | |||
966 | case RTF_HIGHLIGHT: | |||
967 | { | |||
968 | auto pValue = new RTFValue(sal_uInt32(nParam ? getColorTable(nParam) : COL_AUTO)); | |||
969 | m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_highlight, pValue); | |||
970 | } | |||
971 | break; | |||
972 | case RTF_UP: | |||
973 | case RTF_DN: | |||
974 | { | |||
975 | auto pValue = new RTFValue(nParam * (nKeyword == RTF_UP ? 1 : -1)); | |||
976 | m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_position, pValue); | |||
977 | } | |||
978 | break; | |||
979 | case RTF_HORZVERT: | |||
980 | { | |||
981 | auto pValue = new RTFValue(int(true)); | |||
982 | m_aStates.top().getCharacterAttributes().set(NS_ooxml::LN_CT_EastAsianLayout_vert, | |||
983 | pValue); | |||
984 | if (nParam) | |||
985 | // rotate fits to a single line | |||
986 | m_aStates.top().getCharacterAttributes().set( | |||
987 | NS_ooxml::LN_CT_EastAsianLayout_vertCompress, pValue); | |||
988 | } | |||
989 | break; | |||
990 | case RTF_EXPND: | |||
991 | { | |||
992 | // Convert quarter-points to twentieths of a point | |||
993 | auto pValue = new RTFValue(nParam * 5); | |||
994 | m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_spacing, pValue); | |||
995 | } | |||
996 | break; | |||
997 | case RTF_TWOINONE: | |||
998 | { | |||
999 | auto pValue = new RTFValue(int(true)); | |||
1000 | m_aStates.top().getCharacterAttributes().set(NS_ooxml::LN_CT_EastAsianLayout_combine, | |||
1001 | pValue); | |||
1002 | Id nId = 0; | |||
1003 | switch (nParam) | |||
1004 | { | |||
1005 | case 0: | |||
1006 | nId = NS_ooxml::LN_Value_ST_CombineBrackets_none; | |||
1007 | break; | |||
1008 | case 1: | |||
1009 | nId = NS_ooxml::LN_Value_ST_CombineBrackets_round; | |||
1010 | break; | |||
1011 | case 2: | |||
1012 | nId = NS_ooxml::LN_Value_ST_CombineBrackets_square; | |||
1013 | break; | |||
1014 | case 3: | |||
1015 | nId = NS_ooxml::LN_Value_ST_CombineBrackets_angle; | |||
1016 | break; | |||
1017 | case 4: | |||
1018 | nId = NS_ooxml::LN_Value_ST_CombineBrackets_curly; | |||
1019 | break; | |||
1020 | } | |||
1021 | if (nId > 0) | |||
1022 | m_aStates.top().getCharacterAttributes().set( | |||
1023 | NS_ooxml::LN_CT_EastAsianLayout_combineBrackets, new RTFValue(nId)); | |||
1024 | } | |||
1025 | break; | |||
1026 | case RTF_SL: | |||
1027 | { | |||
1028 | // This is similar to RTF_ABSH, negative value means 'exact', positive means 'at least'. | |||
1029 | tools::SvRef<RTFValue> pValue( | |||
1030 | new RTFValue(NS_ooxml::LN_Value_doc_ST_LineSpacingRule_atLeast)); | |||
1031 | if (nParam < 0) | |||
1032 | { | |||
1033 | pValue = new RTFValue(NS_ooxml::LN_Value_doc_ST_LineSpacingRule_exact); | |||
1034 | pIntValue = new RTFValue(-nParam); | |||
1035 | } | |||
1036 | m_aStates.top().getParagraphAttributes().set(NS_ooxml::LN_CT_Spacing_lineRule, pValue); | |||
1037 | m_aStates.top().getParagraphAttributes().set(NS_ooxml::LN_CT_Spacing_line, pIntValue); | |||
1038 | } | |||
1039 | break; | |||
1040 | case RTF_SLMULT: | |||
1041 | if (nParam > 0) | |||
1042 | { | |||
1043 | auto pValue = new RTFValue(NS_ooxml::LN_Value_doc_ST_LineSpacingRule_auto); | |||
1044 | m_aStates.top().getParagraphAttributes().set(NS_ooxml::LN_CT_Spacing_lineRule, | |||
1045 | pValue); | |||
1046 | } | |||
1047 | break; | |||
1048 | case RTF_BRDRW: | |||
1049 | { | |||
1050 | // dmapper expects it in 1/8 pt, we have it in twip - but avoid rounding 1 to 0 | |||
1051 | if (nParam > 1) | |||
1052 | nParam = nParam * 2 / 5; | |||
1053 | auto pValue = new RTFValue(nParam); | |||
1054 | putBorderProperty(m_aStates, NS_ooxml::LN_CT_Border_sz, pValue); | |||
1055 | } | |||
1056 | break; | |||
1057 | case RTF_BRDRCF: | |||
1058 | { | |||
1059 | auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam))); | |||
1060 | putBorderProperty(m_aStates, NS_ooxml::LN_CT_Border_color, pValue); | |||
1061 | } | |||
1062 | break; | |||
1063 | case RTF_BRSP: | |||
1064 | { | |||
1065 | // dmapper expects it in points, we have it in twip | |||
1066 | auto pValue = new RTFValue(nParam / 20); | |||
1067 | putBorderProperty(m_aStates, NS_ooxml::LN_CT_Border_space, pValue); | |||
1068 | } | |||
1069 | break; | |||
1070 | case RTF_TX: | |||
1071 | { | |||
1072 | m_aStates.top().getTabAttributes().set(NS_ooxml::LN_CT_TabStop_pos, pIntValue); | |||
1073 | auto pValue = new RTFValue(m_aStates.top().getTabAttributes()); | |||
1074 | if (m_aStates.top().getDestination() == Destination::LISTLEVEL) | |||
1075 | putNestedSprm(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_PPrBase_tabs, | |||
1076 | NS_ooxml::LN_CT_Tabs_tab, pValue); | |||
1077 | else | |||
1078 | putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_tabs, | |||
1079 | NS_ooxml::LN_CT_Tabs_tab, pValue); | |||
1080 | m_aStates.top().getTabAttributes().clear(); | |||
1081 | } | |||
1082 | break; | |||
1083 | case RTF_ILVL: | |||
1084 | putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_numPr, | |||
1085 | NS_ooxml::LN_CT_NumPr_ilvl, pIntValue); | |||
1086 | break; | |||
1087 | case RTF_LISTTEMPLATEID: | |||
1088 | // This one is not referenced anywhere, so it's pointless to store it at the moment. | |||
1089 | break; | |||
1090 | case RTF_LISTID: | |||
1091 | { | |||
1092 | if (m_aStates.top().getDestination() == Destination::LISTENTRY) | |||
1093 | m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_AbstractNum_abstractNumId, | |||
1094 | pIntValue); | |||
1095 | else if (m_aStates.top().getDestination() == Destination::LISTOVERRIDEENTRY) | |||
1096 | m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Num_abstractNumId, pIntValue); | |||
1097 | m_aStates.top().setCurrentListIndex(nParam); | |||
1098 | } | |||
1099 | break; | |||
1100 | case RTF_LS: | |||
1101 | { | |||
1102 | if (m_aStates.top().getDestination() == Destination::LISTOVERRIDEENTRY) | |||
1103 | { | |||
1104 | m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_AbstractNum_nsid, | |||
1105 | pIntValue); | |||
1106 | m_aStates.top().setCurrentListOverrideIndex(nParam); | |||
1107 | } | |||
1108 | else | |||
1109 | { | |||
1110 | // Insert at the start, so properties inherited from the list | |||
1111 | // can be overridden by direct formatting. But still allow the | |||
1112 | // case when old-style paragraph numbering is already | |||
1113 | // tokenized. | |||
1114 | putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_numPr, | |||
1115 | NS_ooxml::LN_CT_NumPr_numId, pIntValue, RTFOverwrite::YES_PREPEND); | |||
1116 | } | |||
1117 | } | |||
1118 | break; | |||
1119 | case RTF_UC: | |||
1120 | if ((SAL_MIN_INT16((sal_Int16) (-0x7FFF - 1)) <= nParam) && (nParam <= SAL_MAX_INT16((sal_Int16) 0x7FFF))) | |||
1121 | m_aStates.top().setUc(nParam); | |||
1122 | break; | |||
1123 | case RTF_U: | |||
1124 | // sal_Unicode is unsigned 16-bit, RTF may represent that as a | |||
1125 | // signed SAL_MIN_INT16..SAL_MAX_INT16 or 0..SAL_MAX_UINT16. The | |||
1126 | // static_cast() will do the right thing. | |||
1127 | if ((SAL_MIN_INT16((sal_Int16) (-0x7FFF - 1)) <= nParam) && (nParam <= SAL_MAX_UINT16((sal_uInt16) 0xFFFF))) | |||
1128 | { | |||
1129 | if (m_aStates.top().getDestination() == Destination::LEVELNUMBERS) | |||
1130 | { | |||
1131 | if (nParam != ';') | |||
1132 | m_aStates.top().getLevelNumbers().push_back(sal_Int32(nParam)); | |||
1133 | else | |||
1134 | // ';' in \u form is not considered valid. | |||
1135 | m_aStates.top().setLevelNumbersValid(false); | |||
1136 | } | |||
1137 | else | |||
1138 | m_aUnicodeBuffer.append(static_cast<sal_Unicode>(nParam)); | |||
1139 | m_aStates.top().getCharsToSkip() = m_aStates.top().getUc(); | |||
1140 | } | |||
1141 | break; | |||
1142 | case RTF_LEVELFOLLOW: | |||
1143 | { | |||
1144 | OUString sValue; | |||
1145 | switch (nParam) | |||
1146 | { | |||
1147 | case 0: | |||
1148 | sValue = "tab"; | |||
1149 | break; | |||
1150 | case 1: | |||
1151 | sValue = "space"; | |||
1152 | break; | |||
1153 | case 2: | |||
1154 | sValue = "nothing"; | |||
1155 | break; | |||
1156 | } | |||
1157 | if (!sValue.isEmpty()) | |||
1158 | m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Lvl_suff, new RTFValue(sValue)); | |||
1159 | } | |||
1160 | break; | |||
1161 | case RTF_FPRQ: | |||
1162 | { | |||
1163 | sal_Int32 nValue = 0; | |||
1164 | switch (nParam) | |||
1165 | { | |||
1166 | case 0: | |||
1167 | nValue = NS_ooxml::LN_Value_ST_Pitch_default; | |||
1168 | break; | |||
1169 | case 1: | |||
1170 | nValue = NS_ooxml::LN_Value_ST_Pitch_fixed; | |||
1171 | break; | |||
1172 | case 2: | |||
1173 | nValue = NS_ooxml::LN_Value_ST_Pitch_variable; | |||
1174 | break; | |||
1175 | } | |||
1176 | if (nValue) | |||
1177 | { | |||
1178 | RTFSprms aAttributes; | |||
1179 | aAttributes.set(NS_ooxml::LN_CT_Pitch_val, new RTFValue(nValue)); | |||
1180 | m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Font_pitch, | |||
1181 | new RTFValue(aAttributes)); | |||
1182 | } | |||
1183 | } | |||
1184 | break; | |||
1185 | case RTF_LISTOVERRIDECOUNT: | |||
1186 | // Ignore this for now, the exporter always emits it with a zero parameter. | |||
1187 | break; | |||
1188 | case RTF_PICSCALEX: | |||
1189 | m_aStates.top().getPicture().nScaleX = nParam; | |||
1190 | break; | |||
1191 | case RTF_PICSCALEY: | |||
1192 | m_aStates.top().getPicture().nScaleY = nParam; | |||
1193 | break; | |||
1194 | case RTF_PICW: | |||
1195 | m_aStates.top().getPicture().nWidth = nParam; | |||
1196 | break; | |||
1197 | case RTF_PICH: | |||
1198 | m_aStates.top().getPicture().nHeight = nParam; | |||
1199 | break; | |||
1200 | case RTF_PICWGOAL: | |||
1201 | m_aStates.top().getPicture().nGoalWidth = convertTwipToMm100(nParam); | |||
1202 | break; | |||
1203 | case RTF_PICHGOAL: | |||
1204 | m_aStates.top().getPicture().nGoalHeight = convertTwipToMm100(nParam); | |||
1205 | break; | |||
1206 | case RTF_PICCROPL: | |||
1207 | m_aStates.top().getPicture().nCropL = convertTwipToMm100(nParam); | |||
1208 | break; | |||
1209 | case RTF_PICCROPR: | |||
1210 | m_aStates.top().getPicture().nCropR = convertTwipToMm100(nParam); | |||
1211 | break; | |||
1212 | case RTF_PICCROPT: | |||
1213 | m_aStates.top().getPicture().nCropT = convertTwipToMm100(nParam); | |||
1214 | break; | |||
1215 | case RTF_PICCROPB: | |||
1216 | m_aStates.top().getPicture().nCropB = convertTwipToMm100(nParam); | |||
1217 | break; | |||
1218 | case RTF_SHPWRK: | |||
1219 | { | |||
1220 | int nValue = 0; | |||
1221 | switch (nParam) | |||
1222 | { | |||
1223 | case 0: | |||
1224 | nValue = NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_bothSides; | |||
1225 | break; | |||
1226 | case 1: | |||
1227 | nValue = NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_left; | |||
1228 | break; | |||
1229 | case 2: | |||
1230 | nValue = NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_right; | |||
1231 | break; | |||
1232 | case 3: | |||
1233 | nValue = NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_largest; | |||
1234 | break; | |||
1235 | default: | |||
1236 | break; | |||
1237 | } | |||
1238 | auto pValue = new RTFValue(nValue); | |||
1239 | RTFValue::Pointer_t pTight | |||
1240 | = m_aStates.top().getCharacterSprms().find(NS_ooxml::LN_EG_WrapType_wrapTight); | |||
1241 | if (pTight) | |||
1242 | pTight->getAttributes().set(NS_ooxml::LN_CT_WrapTight_wrapText, pValue); | |||
1243 | else | |||
1244 | m_aStates.top().getCharacterAttributes().set(NS_ooxml::LN_CT_WrapSquare_wrapText, | |||
1245 | pValue); | |||
1246 | } | |||
1247 | break; | |||
1248 | case RTF_SHPWR: | |||
1249 | { | |||
1250 | switch (nParam) | |||
1251 | { | |||
1252 | case 1: | |||
1253 | m_aStates.top().getShape().setWrap(text::WrapTextMode_NONE); | |||
1254 | break; | |||
1255 | case 2: | |||
1256 | m_aStates.top().getShape().setWrap(text::WrapTextMode_PARALLEL); | |||
1257 | break; | |||
1258 | case 3: | |||
1259 | m_aStates.top().getShape().setWrap(text::WrapTextMode_THROUGH); | |||
1260 | m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_WrapType_wrapNone, | |||
1261 | new RTFValue()); | |||
1262 | break; | |||
1263 | case 4: | |||
1264 | m_aStates.top().getShape().setWrap(text::WrapTextMode_PARALLEL); | |||
1265 | m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_WrapType_wrapTight, | |||
1266 | new RTFValue()); | |||
1267 | break; | |||
1268 | case 5: | |||
1269 | m_aStates.top().getShape().setWrap(text::WrapTextMode_THROUGH); | |||
1270 | break; | |||
1271 | } | |||
1272 | } | |||
1273 | break; | |||
1274 | case RTF_COLS: | |||
1275 | putNestedAttribute(m_aStates.top().getSectionSprms(), | |||
1276 | NS_ooxml::LN_EG_SectPrContents_cols, NS_ooxml::LN_CT_Columns_num, | |||
1277 | pIntValue); | |||
1278 | break; | |||
1279 | case RTF_COLSX: | |||
1280 | putNestedAttribute(m_aStates.top().getSectionSprms(), | |||
1281 | NS_ooxml::LN_EG_SectPrContents_cols, NS_ooxml::LN_CT_Columns_space, | |||
1282 | pIntValue); | |||
1283 | break; | |||
1284 | case RTF_COLNO: | |||
1285 | putNestedSprm(m_aStates.top().getSectionSprms(), NS_ooxml::LN_EG_SectPrContents_cols, | |||
1286 | NS_ooxml::LN_CT_Columns_col, pIntValue); | |||
1287 | break; | |||
1288 | case RTF_COLW: | |||
1289 | case RTF_COLSR: | |||
1290 | { | |||
1291 | RTFSprms& rAttributes = getLastAttributes(m_aStates.top().getSectionSprms(), | |||
1292 | NS_ooxml::LN_EG_SectPrContents_cols); | |||
1293 | rAttributes.set( | |||
1294 | (nKeyword == RTF_COLW ? NS_ooxml::LN_CT_Column_w : NS_ooxml::LN_CT_Column_space), | |||
1295 | pIntValue); | |||
1296 | } | |||
1297 | break; | |||
1298 | case RTF_PAPERH: | |||
1299 | putNestedAttribute(m_aDefaultState.getSectionSprms(), | |||
1300 | NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_h, | |||
1301 | pIntValue); | |||
1302 | [[fallthrough]]; // set the default + current value | |||
1303 | case RTF_PGHSXN: | |||
1304 | putNestedAttribute(m_aStates.top().getSectionSprms(), | |||
1305 | NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_h, | |||
1306 | pIntValue); | |||
1307 | break; | |||
1308 | case RTF_PAPERW: | |||
1309 | putNestedAttribute(m_aDefaultState.getSectionSprms(), | |||
1310 | NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_w, | |||
1311 | pIntValue); | |||
1312 | [[fallthrough]]; // set the default + current value | |||
1313 | case RTF_PGWSXN: | |||
1314 | putNestedAttribute(m_aStates.top().getSectionSprms(), | |||
1315 | NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_w, | |||
1316 | pIntValue); | |||
1317 | break; | |||
1318 | case RTF_MARGL: | |||
1319 | putNestedAttribute(m_aDefaultState.getSectionSprms(), | |||
1320 | NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_left, | |||
1321 | pIntValue); | |||
1322 | [[fallthrough]]; // set the default + current value | |||
1323 | case RTF_MARGLSXN: | |||
1324 | putNestedAttribute(m_aStates.top().getSectionSprms(), | |||
1325 | NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_left, | |||
1326 | pIntValue); | |||
1327 | break; | |||
1328 | case RTF_MARGR: | |||
1329 | putNestedAttribute(m_aDefaultState.getSectionSprms(), | |||
1330 | NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_right, | |||
1331 | pIntValue); | |||
1332 | [[fallthrough]]; // set the default + current value | |||
1333 | case RTF_MARGRSXN: | |||
1334 | putNestedAttribute(m_aStates.top().getSectionSprms(), | |||
1335 | NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_right, | |||
1336 | pIntValue); | |||
1337 | break; | |||
1338 | case RTF_MARGT: | |||
1339 | putNestedAttribute(m_aDefaultState.getSectionSprms(), | |||
1340 | NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_top, | |||
1341 | pIntValue); | |||
1342 | [[fallthrough]]; // set the default + current value | |||
1343 | case RTF_MARGTSXN: | |||
1344 | putNestedAttribute(m_aStates.top().getSectionSprms(), | |||
1345 | NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_top, | |||
1346 | pIntValue); | |||
1347 | break; | |||
1348 | case RTF_MARGB: | |||
1349 | putNestedAttribute(m_aDefaultState.getSectionSprms(), | |||
1350 | NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_bottom, | |||
1351 | pIntValue); | |||
1352 | [[fallthrough]]; // set the default + current value | |||
1353 | case RTF_MARGBSXN: | |||
1354 | putNestedAttribute(m_aStates.top().getSectionSprms(), | |||
1355 | NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_bottom, | |||
1356 | pIntValue); | |||
1357 | break; | |||
1358 | case RTF_HEADERY: | |||
1359 | putNestedAttribute(m_aStates.top().getSectionSprms(), | |||
1360 | NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_header, | |||
1361 | pIntValue); | |||
1362 | break; | |||
1363 | case RTF_FOOTERY: | |||
1364 | putNestedAttribute(m_aStates.top().getSectionSprms(), | |||
1365 | NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_footer, | |||
1366 | pIntValue); | |||
1367 | break; | |||
1368 | case RTF_DEFTAB: | |||
1369 | m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_defaultTabStop, pIntValue); | |||
1370 | break; | |||
1371 | case RTF_LINEMOD: | |||
1372 | putNestedAttribute(m_aStates.top().getSectionSprms(), | |||
1373 | NS_ooxml::LN_EG_SectPrContents_lnNumType, | |||
1374 | NS_ooxml::LN_CT_LineNumber_countBy, pIntValue); | |||
1375 | break; | |||
1376 | case RTF_LINEX: | |||
1377 | if (nParam) | |||
1378 | putNestedAttribute(m_aStates.top().getSectionSprms(), | |||
1379 | NS_ooxml::LN_EG_SectPrContents_lnNumType, | |||
1380 | NS_ooxml::LN_CT_LineNumber_distance, pIntValue); | |||
1381 | break; | |||
1382 | case RTF_LINESTARTS: | |||
1383 | { | |||
1384 | // OOXML <w:lnNumType w:start="..."/> is 0-based, RTF is 1-based. | |||
1385 | auto pStart = tools::make_ref<RTFValue>(nParam - 1); | |||
1386 | putNestedAttribute(m_aStates.top().getSectionSprms(), | |||
1387 | NS_ooxml::LN_EG_SectPrContents_lnNumType, | |||
1388 | NS_ooxml::LN_CT_LineNumber_start, pStart); | |||
1389 | } | |||
1390 | break; | |||
1391 | case RTF_REVAUTH: | |||
1392 | case RTF_REVAUTHDEL: | |||
1393 | { | |||
1394 | auto pValue = new RTFValue(m_aAuthors[nParam]); | |||
1395 | putNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_trackchange, | |||
1396 | NS_ooxml::LN_CT_TrackChange_author, pValue); | |||
1397 | } | |||
1398 | break; | |||
1399 | case RTF_REVDTTM: | |||
1400 | case RTF_REVDTTMDEL: | |||
1401 | { | |||
1402 | OUString aStr( | |||
1403 | OStringToOUString(DTTM22OString(nParam), m_aStates.top().getCurrentEncoding())); | |||
1404 | auto pValue = new RTFValue(aStr); | |||
1405 | putNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_trackchange, | |||
1406 | NS_ooxml::LN_CT_TrackChange_date, pValue); | |||
1407 | } | |||
1408 | break; | |||
1409 | case RTF_SHPLEFT: | |||
1410 | m_aStates.top().getShape().setLeft(convertTwipToMm100(nParam)); | |||
1411 | break; | |||
1412 | case RTF_SHPTOP: | |||
1413 | m_aStates.top().getShape().setTop(convertTwipToMm100(nParam)); | |||
1414 | break; | |||
1415 | case RTF_SHPRIGHT: | |||
1416 | m_aStates.top().getShape().setRight(convertTwipToMm100(nParam)); | |||
1417 | break; | |||
1418 | case RTF_SHPBOTTOM: | |||
1419 | m_aStates.top().getShape().setBottom(convertTwipToMm100(nParam)); | |||
1420 | break; | |||
1421 | case RTF_SHPZ: | |||
1422 | m_aStates.top().getShape().setZ(nParam); | |||
1423 | break; | |||
1424 | case RTF_FFTYPE: | |||
1425 | switch (nParam) | |||
1426 | { | |||
1427 | case 0: | |||
1428 | m_nFormFieldType = RTFFormFieldType::TEXT; | |||
1429 | break; | |||
1430 | case 1: | |||
1431 | m_nFormFieldType = RTFFormFieldType::CHECKBOX; | |||
1432 | break; | |||
1433 | case 2: | |||
1434 | m_nFormFieldType = RTFFormFieldType::LIST; | |||
1435 | break; | |||
1436 | default: | |||
1437 | m_nFormFieldType = RTFFormFieldType::NONE; | |||
1438 | break; | |||
1439 | } | |||
1440 | break; | |||
1441 | case RTF_FFDEFRES: | |||
1442 | if (m_nFormFieldType == RTFFormFieldType::CHECKBOX) | |||
1443 | m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFCheckBox_default, pIntValue); | |||
1444 | else if (m_nFormFieldType == RTFFormFieldType::LIST) | |||
1445 | m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFDDList_default, pIntValue); | |||
1446 | break; | |||
1447 | case RTF_FFRES: | |||
1448 | // 25 means undefined, see [MS-DOC] 2.9.79, FFDataBits. | |||
1449 | if (m_nFormFieldType == RTFFormFieldType::CHECKBOX && nParam != 25) | |||
1450 | m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFCheckBox_checked, pIntValue); | |||
1451 | else if (m_nFormFieldType == RTFFormFieldType::LIST) | |||
1452 | m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFDDList_result, pIntValue); | |||
1453 | break; | |||
1454 | case RTF_EDMINS: | |||
1455 | if (m_xDocumentProperties.is()) | |||
1456 | { | |||
1457 | // tdf#116851 some RTF may be malformed | |||
1458 | if (nParam < 0) | |||
1459 | nParam = -nParam; | |||
1460 | m_xDocumentProperties->setEditingDuration(nParam); | |||
1461 | } | |||
1462 | break; | |||
1463 | case RTF_NOFPAGES: | |||
1464 | case RTF_NOFWORDS: | |||
1465 | case RTF_NOFCHARS: | |||
1466 | case RTF_NOFCHARSWS: | |||
1467 | if (m_xDocumentProperties.is()) | |||
1468 | { | |||
1469 | comphelper::SequenceAsHashMap aSeq = m_xDocumentProperties->getDocumentStatistics(); | |||
1470 | OUString aName; | |||
1471 | switch (nKeyword) | |||
1472 | { | |||
1473 | case RTF_NOFPAGES: | |||
1474 | aName = "PageCount"; | |||
1475 | nParam = 99; | |||
1476 | break; | |||
1477 | case RTF_NOFWORDS: | |||
1478 | aName = "WordCount"; | |||
1479 | break; | |||
1480 | case RTF_NOFCHARS: | |||
1481 | aName = "CharacterCount"; | |||
1482 | break; | |||
1483 | case RTF_NOFCHARSWS: | |||
1484 | aName = "NonWhitespaceCharacterCount"; | |||
1485 | break; | |||
1486 | default: | |||
1487 | break; | |||
1488 | } | |||
1489 | if (!aName.isEmpty()) | |||
1490 | { | |||
1491 | aSeq[aName] <<= sal_Int32(nParam); | |||
1492 | m_xDocumentProperties->setDocumentStatistics(aSeq.getAsConstNamedValueList()); | |||
1493 | } | |||
1494 | } | |||
1495 | break; | |||
1496 | case RTF_VERSION: | |||
1497 | if (m_xDocumentProperties.is()) | |||
1498 | m_xDocumentProperties->setEditingCycles(nParam); | |||
1499 | break; | |||
1500 | case RTF_VERN: | |||
1501 | // Ignore this for now, later the RTF writer version could be used to add hacks for older buggy writers. | |||
1502 | break; | |||
1503 | case RTF_FTNSTART: | |||
1504 | putNestedSprm(m_aDefaultState.getParagraphSprms(), | |||
1505 | NS_ooxml::LN_EG_SectPrContents_footnotePr, | |||
1506 | NS_ooxml::LN_EG_FtnEdnNumProps_numStart, pIntValue); | |||
1507 | break; | |||
1508 | case RTF_AFTNSTART: | |||
1509 | putNestedSprm(m_aDefaultState.getParagraphSprms(), | |||
1510 | NS_ooxml::LN_EG_SectPrContents_endnotePr, | |||
1511 | NS_ooxml::LN_EG_FtnEdnNumProps_numStart, pIntValue); | |||
1512 | break; | |||
1513 | case RTF_DFRMTXTX: | |||
1514 | m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_hSpace, nParam); | |||
1515 | break; | |||
1516 | case RTF_DFRMTXTY: | |||
1517 | m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_vSpace, nParam); | |||
1518 | break; | |||
1519 | case RTF_DXFRTEXT: | |||
1520 | { | |||
1521 | m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_hSpace, nParam); | |||
1522 | m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_vSpace, nParam); | |||
1523 | } | |||
1524 | break; | |||
1525 | case RTF_FLYVERT: | |||
1526 | { | |||
1527 | RTFVertOrient aVertOrient(nParam); | |||
1528 | m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign, | |||
1529 | aVertOrient.GetAlign()); | |||
1530 | m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_vAnchor, | |||
1531 | aVertOrient.GetAnchor()); | |||
1532 | } | |||
1533 | break; | |||
1534 | case RTF_FLYHORZ: | |||
1535 | { | |||
1536 | RTFHoriOrient aHoriOrient(nParam); | |||
1537 | m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_xAlign, | |||
1538 | aHoriOrient.GetAlign()); | |||
1539 | m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_hAnchor, | |||
1540 | aHoriOrient.GetAnchor()); | |||
1541 | } | |||
1542 | break; | |||
1543 | case RTF_FLYANCHOR: | |||
1544 | break; | |||
1545 | case RTF_WMETAFILE: | |||
1546 | m_aStates.top().getPicture().eWMetafile = nParam; | |||
1547 | break; | |||
1548 | case RTF_SB: | |||
1549 | putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_spacing, | |||
1550 | NS_ooxml::LN_CT_Spacing_before, pIntValue); | |||
1551 | break; | |||
1552 | case RTF_SA: | |||
1553 | putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_spacing, | |||
1554 | NS_ooxml::LN_CT_Spacing_after, pIntValue); | |||
1555 | break; | |||
1556 | case RTF_DPX: | |||
1557 | m_aStates.top().getDrawingObject().setLeft(convertTwipToMm100(nParam)); | |||
1558 | break; | |||
1559 | case RTF_DPY: | |||
1560 | m_aStates.top().getDrawingObject().setTop(convertTwipToMm100(nParam)); | |||
1561 | break; | |||
1562 | case RTF_DPXSIZE: | |||
1563 | m_aStates.top().getDrawingObject().setRight(convertTwipToMm100(nParam)); | |||
1564 | break; | |||
1565 | case RTF_DPYSIZE: | |||
1566 | m_aStates.top().getDrawingObject().setBottom(convertTwipToMm100(nParam)); | |||
1567 | break; | |||
1568 | case RTF_PNSTART: | |||
1569 | m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Lvl_start, pIntValue); | |||
1570 | break; | |||
1571 | case RTF_PNF: | |||
1572 | { | |||
1573 | auto pValue = new RTFValue(m_aFontNames[getFontIndex(nParam)]); | |||
1574 | RTFSprms aAttributes; | |||
1575 | aAttributes.set(NS_ooxml::LN_CT_Fonts_ascii, pValue); | |||
1576 | putNestedSprm(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_Lvl_rPr, | |||
1577 | NS_ooxml::LN_EG_RPrBase_rFonts, new RTFValue(aAttributes)); | |||
1578 | } | |||
1579 | break; | |||
1580 | case RTF_VIEWSCALE: | |||
1581 | m_aSettingsTableAttributes.set(NS_ooxml::LN_CT_Zoom_percent, pIntValue); | |||
1582 | break; | |||
1583 | case RTF_BIN: | |||
1584 | { | |||
1585 | m_aStates.top().setInternalState(RTFInternalState::BIN); | |||
1586 | m_aStates.top().setBinaryToRead(nParam); | |||
1587 | } | |||
1588 | break; | |||
1589 | case RTF_DPLINECOR: | |||
1590 | m_aStates.top().getDrawingObject().setLineColorR(nParam); | |||
1591 | m_aStates.top().getDrawingObject().setHasLineColor(true); | |||
1592 | break; | |||
1593 | case RTF_DPLINECOG: | |||
1594 | m_aStates.top().getDrawingObject().setLineColorG(nParam); | |||
1595 | m_aStates.top().getDrawingObject().setHasLineColor(true); | |||
1596 | break; | |||
1597 | case RTF_DPLINECOB: | |||
1598 | m_aStates.top().getDrawingObject().setLineColorB(nParam); | |||
1599 | m_aStates.top().getDrawingObject().setHasLineColor(true); | |||
1600 | break; | |||
1601 | case RTF_DPFILLBGCR: | |||
1602 | m_aStates.top().getDrawingObject().setFillColorR(nParam); | |||
1603 | m_aStates.top().getDrawingObject().setHasFillColor(true); | |||
1604 | break; | |||
1605 | case RTF_DPFILLBGCG: | |||
1606 | m_aStates.top().getDrawingObject().setFillColorG(nParam); | |||
1607 | m_aStates.top().getDrawingObject().setHasFillColor(true); | |||
1608 | break; | |||
1609 | case RTF_DPFILLBGCB: | |||
1610 | m_aStates.top().getDrawingObject().setFillColorB(nParam); | |||
1611 | m_aStates.top().getDrawingObject().setHasFillColor(true); | |||
1612 | break; | |||
1613 | case RTF_DODHGT: | |||
1614 | m_aStates.top().getDrawingObject().setDhgt(nParam); | |||
1615 | break; | |||
1616 | case RTF_DPPOLYCOUNT: | |||
1617 | if (nParam >= 0) | |||
1618 | { | |||
1619 | m_aStates.top().getDrawingObject().setPolyLineCount(nParam); | |||
1620 | } | |||
1621 | break; | |||
1622 | case RTF_DPPTX: | |||
1623 | { | |||
1624 | RTFDrawingObject& rDrawingObject = m_aStates.top().getDrawingObject(); | |||
1625 | ||||
1626 | if (rDrawingObject.getPolyLinePoints().empty()) | |||
1627 | dispatchValue(RTF_DPPOLYCOUNT, 2); | |||
1628 | ||||
1629 | rDrawingObject.getPolyLinePoints().emplace_back( | |||
1630 | awt::Point(convertTwipToMm100(nParam), 0)); | |||
1631 | } | |||
1632 | break; | |||
1633 | case RTF_DPPTY: | |||
1634 | { | |||
1635 | RTFDrawingObject& rDrawingObject = m_aStates.top().getDrawingObject(); | |||
1636 | if (!rDrawingObject.getPolyLinePoints().empty()) | |||
1637 | { | |||
1638 | rDrawingObject.getPolyLinePoints().back().Y = convertTwipToMm100(nParam); | |||
1639 | rDrawingObject.setPolyLineCount(rDrawingObject.getPolyLineCount() - 1); | |||
1640 | if (rDrawingObject.getPolyLineCount() == 0 && rDrawingObject.getPropertySet().is()) | |||
1641 | { | |||
1642 | uno::Sequence<uno::Sequence<awt::Point>> aPointSequenceSequence | |||
1643 | = { comphelper::containerToSequence(rDrawingObject.getPolyLinePoints()) }; | |||
1644 | rDrawingObject.getPropertySet()->setPropertyValue( | |||
1645 | "PolyPolygon", uno::Any(aPointSequenceSequence)); | |||
1646 | } | |||
1647 | } | |||
1648 | } | |||
1649 | break; | |||
1650 | case RTF_SHPFBLWTXT: | |||
1651 | // Shape is below text -> send it to the background. | |||
1652 | m_aStates.top().getShape().setInBackground(nParam != 0); | |||
1653 | break; | |||
1654 | case RTF_FI: | |||
1655 | { | |||
1656 | if (m_aStates.top().getDestination() == Destination::LISTLEVEL) | |||
1657 | { | |||
1658 | if (m_aStates.top().getLevelNumbersValid()) | |||
1659 | putNestedAttribute(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_PPrBase_ind, | |||
1660 | NS_ooxml::LN_CT_Ind_firstLine, pIntValue); | |||
1661 | else | |||
1662 | m_aInvalidListLevelFirstIndents[m_nListLevel] = nParam; | |||
1663 | } | |||
1664 | else | |||
1665 | putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind, | |||
1666 | NS_ooxml::LN_CT_Ind_firstLine, pIntValue); | |||
1667 | break; | |||
1668 | } | |||
1669 | case RTF_LI: | |||
1670 | { | |||
1671 | if (m_aStates.top().getDestination() == Destination::LISTLEVEL) | |||
1672 | { | |||
1673 | if (m_aStates.top().getLevelNumbersValid()) | |||
1674 | putNestedAttribute(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_PPrBase_ind, | |||
1675 | NS_ooxml::LN_CT_Ind_left, pIntValue); | |||
1676 | } | |||
1677 | else | |||
1678 | { | |||
1679 | putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind, | |||
1680 | NS_ooxml::LN_CT_Ind_left, pIntValue); | |||
1681 | } | |||
1682 | // It turns out \li should reset the \fi inherited from the stylesheet. | |||
1683 | // So set the direct formatting to zero, if we don't have such direct formatting yet. | |||
1684 | putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind, | |||
1685 | NS_ooxml::LN_CT_Ind_firstLine, new RTFValue(0), | |||
1686 | RTFOverwrite::NO_IGNORE); | |||
1687 | } | |||
1688 | break; | |||
1689 | case RTF_RI: | |||
1690 | putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind, | |||
1691 | NS_ooxml::LN_CT_Ind_right, pIntValue); | |||
1692 | break; | |||
1693 | case RTF_LIN: | |||
1694 | putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind, | |||
1695 | NS_ooxml::LN_CT_Ind_start, pIntValue); | |||
1696 | break; | |||
1697 | case RTF_RIN: | |||
1698 | putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind, | |||
1699 | NS_ooxml::LN_CT_Ind_end, pIntValue); | |||
1700 | break; | |||
1701 | case RTF_OUTLINELEVEL: | |||
1702 | m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_outlineLvl, pIntValue); | |||
1703 | break; | |||
1704 | case RTF_PROPTYPE: | |||
1705 | { | |||
1706 | switch (nParam) | |||
1707 | { | |||
1708 | case 3: | |||
1709 | m_aStates.top().setPropType(cppu::UnoType<sal_Int32>::get()); | |||
1710 | break; | |||
1711 | case 5: | |||
1712 | m_aStates.top().setPropType(cppu::UnoType<double>::get()); | |||
1713 | break; | |||
1714 | case 11: | |||
1715 | m_aStates.top().setPropType(cppu::UnoType<bool>::get()); | |||
1716 | break; | |||
1717 | case 30: | |||
1718 | m_aStates.top().setPropType(cppu::UnoType<OUString>::get()); | |||
1719 | break; | |||
1720 | case 64: | |||
1721 | m_aStates.top().setPropType(cppu::UnoType<util::DateTime>::get()); | |||
1722 | break; | |||
1723 | } | |||
1724 | } | |||
1725 | break; | |||
1726 | case RTF_DIBITMAP: | |||
1727 | m_aStates.top().getPicture().eStyle = RTFBmpStyle::DIBITMAP; | |||
1728 | break; | |||
1729 | case RTF_TRWWIDTHA: | |||
1730 | m_aStates.top().setTableRowWidthAfter(nParam); | |||
1731 | break; | |||
1732 | case RTF_ANIMTEXT: | |||
1733 | { | |||
1734 | Id nId = 0; | |||
1735 | switch (nParam) | |||
1736 | { | |||
1737 | case 0: | |||
1738 | nId = NS_ooxml::LN_Value_ST_TextEffect_none; | |||
1739 | break; | |||
1740 | case 2: | |||
1741 | nId = NS_ooxml::LN_Value_ST_TextEffect_blinkBackground; | |||
1742 | break; | |||
1743 | } | |||
1744 | ||||
1745 | if (nId > 0) | |||
1746 | m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_effect, | |||
1747 | new RTFValue(nId)); | |||
1748 | break; | |||
1749 | } | |||
1750 | case RTF_VIEWBKSP: | |||
1751 | { | |||
1752 | m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_displayBackgroundShape, pIntValue); | |||
1753 | // Send this token immediately, if it only appears before the first | |||
1754 | // run, it will be too late, we ignored the background shape already by then. | |||
1755 | outputSettingsTable(); | |||
1756 | break; | |||
1757 | } | |||
1758 | case RTF_STEXTFLOW: | |||
1759 | { | |||
1760 | Id nId = 0; | |||
1761 | switch (nParam) | |||
1762 | { | |||
1763 | case 0: | |||
1764 | nId = NS_ooxml::LN_Value_ST_TextDirection_lrTb; | |||
1765 | break; | |||
1766 | case 1: | |||
1767 | nId = NS_ooxml::LN_Value_ST_TextDirection_tbRl; | |||
1768 | break; | |||
1769 | } | |||
1770 | ||||
1771 | if (nId > 0) | |||
1772 | { | |||
1773 | m_aStates.top().getSectionSprms().set(NS_ooxml::LN_EG_SectPrContents_textDirection, | |||
1774 | new RTFValue(nId)); | |||
1775 | } | |||
1776 | } | |||
1777 | break; | |||
1778 | default: | |||
1779 | { | |||
1780 | SAL_INFO("writerfilter", "TODO handle value '" << keywordToString(nKeyword) << "'")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "writerfilter")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break ; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "TODO handle value '" << keywordToString(nKeyword) << "'") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdispatchvalue.cxx" ":" "1780" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "TODO handle value '" << keywordToString (nKeyword) << "'"), 0); } else { ::std::ostringstream sal_detail_stream ; sal_detail_stream << "TODO handle value '" << keywordToString (nKeyword) << "'"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("writerfilter"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdispatchvalue.cxx" ":" "1780" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "TODO handle value '" << keywordToString(nKeyword ) << "'") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("writerfilter"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdispatchvalue.cxx" ":" "1780" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "TODO handle value '" << keywordToString (nKeyword) << "'"), 0); } else { ::std::ostringstream sal_detail_stream ; sal_detail_stream << "TODO handle value '" << keywordToString (nKeyword) << "'"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("writerfilter"), ("/home/maarten/src/libreoffice/core/writerfilter/source/rtftok/rtfdispatchvalue.cxx" ":" "1780" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1781 | aSkip.setParsed(false); | |||
1782 | } | |||
1783 | break; | |||
1784 | } | |||
1785 | return RTFError::OK; | |||
1786 | } | |||
1787 | ||||
1788 | } // namespace rtftok | |||
1789 | } // namespace writerfilter | |||
1790 | ||||
1791 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ | |||
2 | /* | |||
3 | * This file is part of the LibreOffice project. | |||
4 | * | |||
5 | * This Source Code Form is subject to the terms of the Mozilla Public | |||
6 | * License, v. 2.0. If a copy of the MPL was not distributed with this | |||
7 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. | |||
8 | * | |||
9 | * This file incorporates work covered by the following license notice: | |||
10 | * | |||
11 | * Licensed to the Apache Software Foundation (ASF) under one or more | |||
12 | * contributor license agreements. See the NOTICE file distributed | |||
13 | * with this work for additional information regarding copyright | |||
14 | * ownership. The ASF licenses this file to you under the Apache | |||
15 | * License, Version 2.0 (the "License"); you may not use this file | |||
16 | * except in compliance with the License. You may obtain a copy of | |||
17 | * the License at http://www.apache.org/licenses/LICENSE-2.0 . | |||
18 | */ | |||
19 | #ifndef INCLUDED_TOOLS_REF_HXX | |||
20 | #define INCLUDED_TOOLS_REF_HXX | |||
21 | ||||
22 | #include <sal/config.h> | |||
23 | #include <cassert> | |||
24 | #include <tools/toolsdllapi.h> | |||
25 | #include <utility> | |||
26 | ||||
27 | /** | |||
28 | This implements similar functionality to boost::intrusive_ptr | |||
29 | */ | |||
30 | ||||
31 | namespace tools { | |||
32 | ||||
33 | /** T must be a class that extends SvRefBase */ | |||
34 | template<typename T> class SAL_DLLPUBLIC_RTTI__attribute__ ((type_visibility("default"))) SvRef final { | |||
35 | public: | |||
36 | SvRef(): pObj(nullptr) {} | |||
37 | ||||
38 | SvRef(SvRef&& rObj) noexcept | |||
39 | { | |||
40 | pObj = rObj.pObj; | |||
41 | rObj.pObj = nullptr; | |||
42 | } | |||
43 | ||||
44 | SvRef(SvRef const & rObj): pObj(rObj.pObj) | |||
45 | { | |||
46 | if (pObj != nullptr) pObj->AddNextRef(); | |||
47 | } | |||
48 | ||||
49 | SvRef(T * pObjP): pObj(pObjP) | |||
50 | { | |||
51 | if (pObj != nullptr) pObj->AddFirstRef(); | |||
52 | } | |||
53 | ||||
54 | ~SvRef() | |||
55 | { | |||
56 | if (pObj != nullptr) pObj->ReleaseRef(); | |||
57 | } | |||
58 | ||||
59 | void clear() | |||
60 | { | |||
61 | if (pObj != nullptr) { | |||
62 | T * pRefObj = pObj; | |||
63 | pObj = nullptr; | |||
64 | pRefObj->ReleaseRef(); | |||
65 | } | |||
66 | } | |||
67 | ||||
68 | SvRef & operator =(SvRef const & rObj) | |||
69 | { | |||
70 | if (rObj.pObj != nullptr) { | |||
71 | rObj.pObj->AddNextRef(); | |||
72 | } | |||
73 | T * pRefObj = pObj; | |||
74 | pObj = rObj.pObj; | |||
75 | if (pRefObj != nullptr) { | |||
76 | pRefObj->ReleaseRef(); | |||
77 | } | |||
78 | return *this; | |||
79 | } | |||
80 | ||||
81 | SvRef & operator =(SvRef && rObj) | |||
82 | { | |||
83 | if (pObj != nullptr) { | |||
84 | pObj->ReleaseRef(); | |||
85 | } | |||
86 | pObj = rObj.pObj; | |||
87 | rObj.pObj = nullptr; | |||
| ||||
88 | return *this; | |||
89 | } | |||
90 | ||||
91 | bool is() const { return pObj != nullptr; } | |||
92 | ||||
93 | explicit operator bool() const { return is(); } | |||
94 | ||||
95 | T * get() const { return pObj; } | |||
96 | ||||
97 | T * operator ->() const { assert(pObj != nullptr)(static_cast <bool> (pObj != nullptr) ? void (0) : __assert_fail ("pObj != nullptr", "/home/maarten/src/libreoffice/core/include/tools/ref.hxx" , 97, __extension__ __PRETTY_FUNCTION__)); return pObj; } | |||
98 | ||||
99 | T & operator *() const { assert(pObj != nullptr)(static_cast <bool> (pObj != nullptr) ? void (0) : __assert_fail ("pObj != nullptr", "/home/maarten/src/libreoffice/core/include/tools/ref.hxx" , 99, __extension__ __PRETTY_FUNCTION__)); return *pObj; } | |||
100 | ||||
101 | bool operator ==(const SvRef<T> &rhs) const { return pObj == rhs.pObj; } | |||
102 | bool operator !=(const SvRef<T> &rhs) const { return !(*this == rhs); } | |||
103 | ||||
104 | private: | |||
105 | T * pObj; | |||
106 | }; | |||
107 | ||||
108 | /** | |||
109 | * This implements similar functionality to std::make_shared. | |||
110 | */ | |||
111 | template<typename T, typename... Args> | |||
112 | SvRef<T> make_ref(Args&& ... args) | |||
113 | { | |||
114 | return SvRef<T>(new T(std::forward<Args>(args)...)); | |||
115 | } | |||
116 | ||||
117 | } | |||
118 | ||||
119 | /** Classes that want to be referenced-counted via SvRef<T>, should extend this base class */ | |||
120 | class TOOLS_DLLPUBLIC__attribute__ ((visibility("default"))) SvRefBase | |||
121 | { | |||
122 | // work around a clang 3.5 optimization bug: if the bNoDelete is *first* | |||
123 | // it mis-compiles "if (--nRefCount == 0)" and never deletes any object | |||
124 | unsigned int nRefCount : 31; | |||
125 | // the only reason this is not bool is because MSVC cannot handle mixed type bitfields | |||
126 | unsigned int bNoDelete : 1; | |||
127 | ||||
128 | protected: | |||
129 | virtual ~SvRefBase() COVERITY_NOEXCEPT_FALSE; | |||
130 | ||||
131 | public: | |||
132 | SvRefBase() : nRefCount(0), bNoDelete(1) {} | |||
133 | SvRefBase(const SvRefBase &) : nRefCount(0), bNoDelete(1) {} | |||
134 | ||||
135 | SvRefBase & operator=(const SvRefBase &) { return *this; } | |||
136 | ||||
137 | void RestoreNoDelete() | |||
138 | { bNoDelete = 1; } | |||
139 | ||||
140 | void AddNextRef() | |||
141 | { | |||
142 | assert( nRefCount < (1 << 30) && "Do not add refs to dead objects" )(static_cast <bool> (nRefCount < (1 << 30) && "Do not add refs to dead objects") ? void (0) : __assert_fail ("nRefCount < (1 << 30) && \"Do not add refs to dead objects\"" , "/home/maarten/src/libreoffice/core/include/tools/ref.hxx", 142, __extension__ __PRETTY_FUNCTION__)); | |||
143 | ++nRefCount; | |||
144 | } | |||
145 | ||||
146 | void AddFirstRef() | |||
147 | { | |||
148 | assert( nRefCount < (1 << 30) && "Do not add refs to dead objects" )(static_cast <bool> (nRefCount < (1 << 30) && "Do not add refs to dead objects") ? void (0) : __assert_fail ("nRefCount < (1 << 30) && \"Do not add refs to dead objects\"" , "/home/maarten/src/libreoffice/core/include/tools/ref.hxx", 148, __extension__ __PRETTY_FUNCTION__)); | |||
149 | if( bNoDelete ) | |||
150 | bNoDelete = 0; | |||
151 | ++nRefCount; | |||
152 | } | |||
153 | ||||
154 | void ReleaseRef() | |||
155 | { | |||
156 | assert( nRefCount >= 1)(static_cast <bool> (nRefCount >= 1) ? void (0) : __assert_fail ("nRefCount >= 1", "/home/maarten/src/libreoffice/core/include/tools/ref.hxx" , 156, __extension__ __PRETTY_FUNCTION__)); | |||
157 | if( --nRefCount == 0 && !bNoDelete) | |||
158 | { | |||
159 | // I'm not sure about the original purpose of this line, but right now | |||
160 | // it serves the purpose that anything that attempts to do an AddRef() | |||
161 | // after an object is deleted will trip an assert. | |||
162 | nRefCount = 1 << 30; | |||
163 | delete this; | |||
164 | } | |||
165 | } | |||
166 | ||||
167 | unsigned int GetRefCount() const | |||
168 | { return nRefCount; } | |||
169 | }; | |||
170 | ||||
171 | template<typename T> | |||
172 | class SvCompatWeakBase; | |||
173 | ||||
174 | /** SvCompatWeakHdl acts as an intermediary between SvCompatWeakRef<T> and T. | |||
175 | */ | |||
176 | template<typename T> | |||
177 | class SvCompatWeakHdl final : public SvRefBase | |||
178 | { | |||
179 | friend class SvCompatWeakBase<T>; | |||
180 | T* _pObj; | |||
181 | ||||
182 | SvCompatWeakHdl( T* pObj ) : _pObj( pObj ) {} | |||
183 | ||||
184 | public: | |||
185 | void ResetWeakBase( ) { _pObj = nullptr; } | |||
186 | T* GetObj() { return _pObj; } | |||
187 | }; | |||
188 | ||||
189 | /** We only have one place that extends this, in include/sfx2/frame.hxx, class SfxFrame. | |||
190 | Its function is to notify the SvCompatWeakHdl when an SfxFrame object is deleted. | |||
191 | */ | |||
192 | template<typename T> | |||
193 | class SvCompatWeakBase | |||
194 | { | |||
195 | tools::SvRef< SvCompatWeakHdl<T> > _xHdl; | |||
196 | ||||
197 | public: | |||
198 | /** Does not use initializer due to compiler warnings, | |||
199 | because the lifetime of the _xHdl object can exceed the lifetime of this class. | |||
200 | */ | |||
201 | SvCompatWeakBase( T* pObj ) { _xHdl = new SvCompatWeakHdl<T>( pObj ); } | |||
202 | ||||
203 | ~SvCompatWeakBase() { _xHdl->ResetWeakBase(); } | |||
204 | ||||
205 | SvCompatWeakHdl<T>* GetHdl() { return _xHdl.get(); } | |||
206 | }; | |||
207 | ||||
208 | /** We only have one weak reference in LO, in include/sfx2/frame.hxx, class SfxFrameWeak. | |||
209 | */ | |||
210 | template<typename T> | |||
211 | class SAL_WARN_UNUSED__attribute__((warn_unused)) SvCompatWeakRef | |||
212 | { | |||
213 | tools::SvRef< SvCompatWeakHdl<T> > _xHdl; | |||
214 | public: | |||
215 | SvCompatWeakRef( ) {} | |||
216 | SvCompatWeakRef( T* pObj ) | |||
217 | { if( pObj ) _xHdl = pObj->GetHdl(); } | |||
218 | #if defined(__COVERITY__) | |||
219 | ~SvCompatWeakRef() COVERITY_NOEXCEPT_FALSE {} | |||
220 | #endif | |||
221 | SvCompatWeakRef& operator = ( T * pObj ) | |||
222 | { _xHdl = pObj ? pObj->GetHdl() : nullptr; return *this; } | |||
223 | bool is() const | |||
224 | { return _xHdl.is() && _xHdl->GetObj(); } | |||
225 | explicit operator bool() const { return is(); } | |||
226 | T* operator -> () const | |||
227 | { return _xHdl.is() ? _xHdl->GetObj() : nullptr; } | |||
228 | operator T* () const | |||
229 | { return _xHdl.is() ? _xHdl->GetObj() : nullptr; } | |||
230 | }; | |||
231 | ||||
232 | #endif | |||
233 | ||||
234 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |