File: | home/maarten/src/libreoffice/core/include/tools/ref.hxx |
Warning: | line 56, column 30 Use of memory after it is freed |
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 | * 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 | #include <optional> | |||
20 | #include "DomainMapperTableManager.hxx" | |||
21 | #include "ConversionHelper.hxx" | |||
22 | #include "MeasureHandler.hxx" | |||
23 | #include "TagLogger.hxx" | |||
24 | #include <com/sun/star/text/SizeType.hpp> | |||
25 | #include <com/sun/star/text/TableColumnSeparator.hpp> | |||
26 | #include <com/sun/star/text/WritingMode2.hpp> | |||
27 | #include <o3tl/numeric.hxx> | |||
28 | #include <o3tl/safeint.hxx> | |||
29 | #include <ooxml/resourceids.hxx> | |||
30 | #include <rtl/math.hxx> | |||
31 | #include <sal/log.hxx> | |||
32 | #include <numeric> | |||
33 | ||||
34 | namespace writerfilter::dmapper { | |||
35 | ||||
36 | using namespace ::com::sun::star; | |||
37 | using namespace ::std; | |||
38 | ||||
39 | DomainMapperTableManager::DomainMapperTableManager() : | |||
40 | m_nRow(0), | |||
41 | m_nCell(), | |||
42 | m_nGridSpan(1), | |||
43 | m_nHeaderRepeat(0), | |||
44 | m_nTableWidth(0), | |||
45 | m_bIsInShape(false), | |||
46 | m_aTmpPosition(), | |||
47 | m_aTmpTableProperties(), | |||
48 | m_bPushCurrentWidth(false), | |||
49 | m_bTableSizeTypeInserted(false), | |||
50 | m_nLayoutType(0), | |||
51 | m_aParagraphsToEndTable(), | |||
52 | m_pTablePropsHandler(new TablePropertiesHandler()) | |||
53 | { | |||
54 | m_pTablePropsHandler->SetTableManager( this ); | |||
55 | } | |||
56 | ||||
57 | ||||
58 | DomainMapperTableManager::~DomainMapperTableManager() | |||
59 | { | |||
60 | } | |||
61 | ||||
62 | bool DomainMapperTableManager::attribute(Id nName, Value const & rValue) | |||
63 | { | |||
64 | bool bRet = true; | |||
65 | ||||
66 | switch (nName) | |||
67 | { | |||
68 | case NS_ooxml::LN_CT_TblLook_val: | |||
69 | { | |||
70 | TablePropertyMapPtr pPropMap(new TablePropertyMap()); | |||
71 | pPropMap->Insert(PROP_TBL_LOOK, uno::makeAny<sal_Int32>(rValue.getInt())); | |||
72 | insertTableProps(pPropMap); | |||
73 | m_aTableLook["val"] <<= static_cast<sal_Int32>(rValue.getInt()); | |||
74 | } | |||
75 | break; | |||
76 | case NS_ooxml::LN_CT_TblLook_noVBand: | |||
77 | m_aTableLook["noVBand"] <<= static_cast<sal_Int32>(rValue.getInt()); | |||
78 | break; | |||
79 | case NS_ooxml::LN_CT_TblLook_noHBand: | |||
80 | m_aTableLook["noHBand"] <<= static_cast<sal_Int32>(rValue.getInt()); | |||
81 | break; | |||
82 | case NS_ooxml::LN_CT_TblLook_lastColumn: | |||
83 | m_aTableLook["lastColumn"] <<= static_cast<sal_Int32>(rValue.getInt()); | |||
84 | break; | |||
85 | case NS_ooxml::LN_CT_TblLook_lastRow: | |||
86 | m_aTableLook["lastRow"] <<= static_cast<sal_Int32>(rValue.getInt()); | |||
87 | break; | |||
88 | case NS_ooxml::LN_CT_TblLook_firstColumn: | |||
89 | m_aTableLook["firstColumn"] <<= static_cast<sal_Int32>(rValue.getInt()); | |||
90 | break; | |||
91 | case NS_ooxml::LN_CT_TblLook_firstRow: | |||
92 | m_aTableLook["firstRow"] <<= static_cast<sal_Int32>(rValue.getInt()); | |||
93 | break; | |||
94 | default: | |||
95 | bRet = false; | |||
96 | } | |||
97 | ||||
98 | return bRet; | |||
99 | } | |||
100 | ||||
101 | void DomainMapperTableManager::finishTableLook() | |||
102 | { | |||
103 | TablePropertyMapPtr pPropMap(new TablePropertyMap()); | |||
| ||||
104 | pPropMap->Insert(META_PROP_TABLE_LOOK, uno::makeAny(m_aTableLook.getAsConstPropertyValueList())); | |||
105 | m_aTableLook.clear(); | |||
106 | insertTableProps(pPropMap); | |||
107 | } | |||
108 | ||||
109 | bool DomainMapperTableManager::sprm(Sprm & rSprm) | |||
110 | { | |||
111 | #ifdef DBG_UTIL | |||
112 | TagLogger::getInstance().startElement("tablemanager.sprm"); | |||
113 | string sSprm = rSprm.toString(); | |||
114 | TagLogger::getInstance().chars(sSprm); | |||
115 | TagLogger::getInstance().endElement(); | |||
116 | #endif | |||
117 | bool bRet = TableManager::sprm(rSprm); | |||
118 | if( !bRet ) | |||
119 | { | |||
120 | bRet = m_pTablePropsHandler->sprm( rSprm ); | |||
121 | } | |||
122 | ||||
123 | if ( !bRet ) | |||
124 | { | |||
125 | bRet = true; | |||
126 | sal_uInt32 nSprmId = rSprm.getId(); | |||
127 | Value::Pointer_t pValue = rSprm.getValue(); | |||
128 | sal_Int32 nIntValue = (pValue ? pValue->getInt() : 0); | |||
129 | switch ( nSprmId ) | |||
130 | { | |||
131 | case NS_ooxml::LN_CT_TblPrBase_tblW: | |||
132 | case NS_ooxml::LN_CT_TblPrBase_tblInd: | |||
133 | { | |||
134 | //contains unit and value | |||
135 | writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps(); | |||
136 | if( pProperties ) | |||
137 | { | |||
138 | MeasureHandlerPtr pMeasureHandler( new MeasureHandler ); | |||
139 | pProperties->resolve(*pMeasureHandler); | |||
140 | TablePropertyMapPtr pPropMap( new TablePropertyMap ); | |||
141 | if (nSprmId == sal_uInt32(NS_ooxml::LN_CT_TblPrBase_tblInd)) | |||
142 | { | |||
143 | pPropMap->setValue( TablePropertyMap::LEFT_MARGIN, pMeasureHandler->getMeasureValue() ); | |||
144 | } | |||
145 | else | |||
146 | { | |||
147 | m_nTableWidth = pMeasureHandler->getMeasureValue(); | |||
148 | if( m_nTableWidth ) | |||
149 | { | |||
150 | pPropMap->setValue( TablePropertyMap::TABLE_WIDTH_TYPE, text::SizeType::FIX ); | |||
151 | pPropMap->setValue( TablePropertyMap::TABLE_WIDTH, m_nTableWidth ); | |||
152 | m_bTableSizeTypeInserted = true; | |||
153 | } | |||
154 | else if( sal::static_int_cast<Id>(pMeasureHandler->getUnit()) == NS_ooxml::LN_Value_ST_TblWidth_pct ) | |||
155 | { | |||
156 | sal_Int32 nPercent = pMeasureHandler->getValue() / 50; | |||
157 | if(nPercent > 100) | |||
158 | nPercent = 100; | |||
159 | pPropMap->setValue( TablePropertyMap::TABLE_WIDTH_TYPE, text::SizeType::VARIABLE ); | |||
160 | pPropMap->setValue( TablePropertyMap::TABLE_WIDTH, nPercent ); | |||
161 | m_bTableSizeTypeInserted = true; | |||
162 | } | |||
163 | else if( sal::static_int_cast<Id>(pMeasureHandler->getUnit()) == NS_ooxml::LN_Value_ST_TblWidth_auto ) | |||
164 | { | |||
165 | /* | |||
166 | This attribute specifies the width type of table. This is used as part of the table layout | |||
167 | algorithm specified by the tblLayout element.(See 17.4.64 and 17.4.65 of the ISO/IEC 29500-1:2011.) | |||
168 | If this value is 'auto', the table layout has to use the preferred widths on the table items to generate | |||
169 | the final sizing of the table, but then must use the contents of each cell to determine final column widths. | |||
170 | (See 17.18.87 of the ISO/IEC 29500-1:2011.) | |||
171 | */ | |||
172 | IntVectorPtr pCellWidths = getCurrentCellWidths(); | |||
173 | // Check whether all cells have fixed widths in the given row of table. | |||
174 | bool bFixed = std::find(pCellWidths->begin(), pCellWidths->end(), -1) == pCellWidths->end(); | |||
175 | if (!bFixed) | |||
176 | { | |||
177 | // Set the width type of table with 'Auto' and set the width value to 0 (as per grid values) | |||
178 | pPropMap->setValue( TablePropertyMap::TABLE_WIDTH_TYPE, text::SizeType::VARIABLE ); | |||
179 | pPropMap->setValue( TablePropertyMap::TABLE_WIDTH, 0 ); | |||
180 | m_bTableSizeTypeInserted = true; | |||
181 | } | |||
182 | else if (getTableDepth() > 1) | |||
183 | { | |||
184 | // tdf#131819 limiting the fix for nested tables temporarily | |||
185 | // TODO revert the fix for tdf#104876 and reopen it | |||
186 | m_bTableSizeTypeInserted = true; | |||
187 | } | |||
188 | } | |||
189 | } | |||
190 | #ifdef DBG_UTIL | |||
191 | pPropMap->dumpXml(); | |||
192 | #endif | |||
193 | insertTableProps(pPropMap); | |||
194 | } | |||
195 | } | |||
196 | break; | |||
197 | case NS_ooxml::LN_CT_TrPrBase_tblHeader: | |||
198 | // if nIntValue == 1 then the row is a repeated header line | |||
199 | // to prevent later rows from increasing the repeating m_nHeaderRepeat is set to NULL when repeating stops | |||
200 | if( nIntValue > 0 && m_nHeaderRepeat == static_cast<int>(m_nRow) ) | |||
201 | { | |||
202 | TablePropertyMapPtr pPropMap( new TablePropertyMap ); | |||
203 | ||||
204 | // FIXME: DOCX tables with more than 10 repeating header lines imported | |||
205 | // without repeating header lines to mimic an MSO workaround for its usability bug. | |||
206 | // Explanation: it's very hard to set and modify repeating header rows in Word, | |||
207 | // often resulting tables with a special workaround: setting all table rows as | |||
208 | // repeating header, because exceeding the pages by "unlimited" header rows turns off the | |||
209 | // table headers automatically in MSO. 10-row limit is a reasonable temporary limit | |||
210 | // to handle DOCX tables with "unlimited" repeating header, till the same "turn off | |||
211 | // exceeding header" feature is ready (see tdf#88496). | |||
212 | #define HEADER_ROW_LIMIT_FOR_MSO_WORKAROUND10 10 | |||
213 | if ( m_nHeaderRepeat == HEADER_ROW_LIMIT_FOR_MSO_WORKAROUND10 ) | |||
214 | { | |||
215 | m_nHeaderRepeat = -1; | |||
216 | pPropMap->Insert( PROP_HEADER_ROW_COUNT, uno::makeAny(sal_Int32(0))); | |||
217 | } | |||
218 | else | |||
219 | { | |||
220 | ++m_nHeaderRepeat; | |||
221 | pPropMap->Insert( PROP_HEADER_ROW_COUNT, uno::makeAny( m_nHeaderRepeat )); | |||
222 | } | |||
223 | insertTableProps(pPropMap); | |||
224 | } | |||
225 | else | |||
226 | { | |||
227 | if ( nIntValue == 0 && m_nRow == 0 ) | |||
228 | { | |||
229 | // explicit tblHeader=0 in the first row must overwrite table style | |||
230 | TablePropertyMapPtr pPropMap( new TablePropertyMap ); | |||
231 | pPropMap->Insert( PROP_HEADER_ROW_COUNT, uno::makeAny(sal_Int32(0))); | |||
232 | insertTableProps(pPropMap); | |||
233 | } | |||
234 | m_nHeaderRepeat = -1; | |||
235 | } | |||
236 | if (nIntValue) | |||
237 | { | |||
238 | // Store the info that this is a header, we'll need that when we apply table styles. | |||
239 | TablePropertyMapPtr pPropMap( new TablePropertyMap ); | |||
240 | pPropMap->Insert( PROP_TBL_HEADER, uno::makeAny(nIntValue)); | |||
241 | insertRowProps(pPropMap); | |||
242 | } | |||
243 | break; | |||
244 | case NS_ooxml::LN_CT_TblPrBase_tblStyle: //table style name | |||
245 | { | |||
246 | TablePropertyMapPtr pPropMap( new TablePropertyMap ); | |||
247 | pPropMap->Insert( META_PROP_TABLE_STYLE_NAME, uno::makeAny( pValue->getString() )); | |||
248 | insertTableProps(pPropMap); | |||
249 | } | |||
250 | break; | |||
251 | case NS_ooxml::LN_CT_TblGridBase_gridCol: | |||
252 | { | |||
253 | if (nIntValue == -1) | |||
254 | getCurrentGrid()->clear(); | |||
255 | else | |||
256 | getCurrentGrid()->push_back( nIntValue ); | |||
257 | } | |||
258 | break; | |||
259 | case NS_ooxml::LN_CT_TcPrBase_vMerge : //vertical merge | |||
260 | { | |||
261 | // values can be: LN_Value_ST_Merge_restart, LN_Value_ST_Merge_continue, in reality the second one is a 0 | |||
262 | TablePropertyMapPtr pMergeProps( new TablePropertyMap ); | |||
263 | pMergeProps->Insert( PROP_VERTICAL_MERGE, uno::makeAny( sal::static_int_cast<Id>(nIntValue) == NS_ooxml::LN_Value_ST_Merge_restart ) ); | |||
264 | cellProps( pMergeProps); | |||
265 | } | |||
266 | break; | |||
267 | case NS_ooxml::LN_CT_TcPrBase_hMerge: | |||
268 | { | |||
269 | // values can be: LN_Value_ST_Merge_restart, LN_Value_ST_Merge_continue, in reality the second one is a 0 | |||
270 | TablePropertyMapPtr pMergeProps(new TablePropertyMap()); | |||
271 | pMergeProps->Insert(PROP_HORIZONTAL_MERGE, uno::makeAny( sal::static_int_cast<Id>(nIntValue) == NS_ooxml::LN_Value_ST_Merge_restart )); | |||
272 | cellProps(pMergeProps); | |||
273 | } | |||
274 | break; | |||
275 | case NS_ooxml::LN_CT_TcPrBase_gridSpan: //number of grid positions spanned by this cell | |||
276 | { | |||
277 | #ifdef DBG_UTIL | |||
278 | TagLogger::getInstance().startElement("tablemanager.GridSpan"); | |||
279 | TagLogger::getInstance().attribute("gridSpan", nIntValue); | |||
280 | TagLogger::getInstance().endElement(); | |||
281 | #endif | |||
282 | m_nGridSpan = nIntValue; | |||
283 | } | |||
284 | break; | |||
285 | case NS_ooxml::LN_CT_TcPrBase_textDirection: | |||
286 | { | |||
287 | TablePropertyMapPtr pPropMap( new TablePropertyMap ); | |||
288 | bool bInsertCellProps = true; | |||
289 | switch ( nIntValue ) | |||
290 | { | |||
291 | case NS_ooxml::LN_Value_ST_TextDirection_tbRl: | |||
292 | // Binary filter takes BiDirection into account ( but I have no idea about that here ) | |||
293 | // or even what it is. But... here's where to handle it if it becomes an issue | |||
294 | pPropMap->Insert( PROP_FRM_DIRECTION, uno::makeAny( text::WritingMode2::TB_RL )); | |||
295 | SAL_INFO( "writerfilter", "Have inserted textDirection " << nIntValue )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() << "Have inserted textDirection " << nIntValue) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("writerfilter"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapperTableManager.cxx" ":" "295" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "Have inserted textDirection " << nIntValue), 0); } else { ::std::ostringstream sal_detail_stream ; sal_detail_stream << "Have inserted textDirection " << nIntValue; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO) , ("writerfilter"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapperTableManager.cxx" ":" "295" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "Have inserted textDirection " << nIntValue ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("writerfilter" ), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapperTableManager.cxx" ":" "295" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "Have inserted textDirection " << nIntValue), 0); } else { ::std::ostringstream sal_detail_stream ; sal_detail_stream << "Have inserted textDirection " << nIntValue; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO) , ("writerfilter"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapperTableManager.cxx" ":" "295" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
296 | break; | |||
297 | case NS_ooxml::LN_Value_ST_TextDirection_btLr: | |||
298 | pPropMap->Insert( PROP_FRM_DIRECTION, uno::makeAny( text::WritingMode2::BT_LR )); | |||
299 | break; | |||
300 | case NS_ooxml::LN_Value_ST_TextDirection_lrTbV: | |||
301 | pPropMap->Insert( PROP_FRM_DIRECTION, uno::makeAny( text::WritingMode2::LR_TB )); | |||
302 | break; | |||
303 | case NS_ooxml::LN_Value_ST_TextDirection_tbRlV: | |||
304 | pPropMap->Insert( PROP_FRM_DIRECTION, uno::makeAny( text::WritingMode2::TB_RL )); | |||
305 | break; | |||
306 | case NS_ooxml::LN_Value_ST_TextDirection_lrTb: | |||
307 | case NS_ooxml::LN_Value_ST_TextDirection_tbLrV: | |||
308 | default: | |||
309 | // Ignore - we can't handle these | |||
310 | bInsertCellProps = false; | |||
311 | break; | |||
312 | } | |||
313 | if ( bInsertCellProps ) | |||
314 | cellProps( pPropMap ); | |||
315 | break; | |||
316 | } | |||
317 | case NS_ooxml::LN_CT_TcPrBase_tcW: | |||
318 | { | |||
319 | // Contains unit and value, but unit is not interesting for | |||
320 | // us, later we'll just distribute these values in a | |||
321 | // 0..10000 scale. | |||
322 | writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps(); | |||
323 | if( pProperties ) | |||
324 | { | |||
325 | MeasureHandlerPtr pMeasureHandler(new MeasureHandler()); | |||
326 | pProperties->resolve(*pMeasureHandler); | |||
327 | if (sal::static_int_cast<Id>(pMeasureHandler->getUnit()) == NS_ooxml::LN_Value_ST_TblWidth_auto) | |||
328 | getCurrentCellWidths()->push_back(sal_Int32(-1)); | |||
329 | else | |||
330 | // store the original value to limit rounding mistakes, if it's there in a recognized measure (twip) | |||
331 | getCurrentCellWidths()->push_back(pMeasureHandler->getMeasureValue() ? pMeasureHandler->getValue() : sal_Int32(0)); | |||
332 | if (getTableDepthDifference() > 0) | |||
333 | m_bPushCurrentWidth = true; | |||
334 | } | |||
335 | } | |||
336 | break; | |||
337 | case NS_ooxml::LN_CT_TblPrBase_tblpPr: | |||
338 | { | |||
339 | writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps(); | |||
340 | // Ignore <w:tblpPr> in shape text, those tables should be always non-floating ones. | |||
341 | if (!m_bIsInShape && pProperties) | |||
342 | { | |||
343 | TablePositionHandlerPtr pHandler = m_aTmpPosition.back(); | |||
344 | if ( !pHandler ) | |||
345 | { | |||
346 | m_aTmpPosition.pop_back(); | |||
347 | pHandler = new TablePositionHandler; | |||
348 | m_aTmpPosition.push_back( pHandler ); | |||
349 | } | |||
350 | pProperties->resolve(*m_aTmpPosition.back()); | |||
351 | } | |||
352 | } | |||
353 | break; | |||
354 | case NS_ooxml::LN_CT_TrPrBase_gridBefore: | |||
355 | setCurrentGridBefore( nIntValue ); | |||
356 | break; | |||
357 | case NS_ooxml::LN_CT_TrPrBase_gridAfter: | |||
358 | setCurrentGridAfter( nIntValue ); | |||
359 | break; | |||
360 | case NS_ooxml::LN_CT_TblPrBase_tblCaption: | |||
361 | // To-Do: Not yet preserved | |||
362 | break; | |||
363 | case NS_ooxml::LN_CT_TblPrBase_tblDescription: | |||
364 | // To-Do: Not yet preserved | |||
365 | break; | |||
366 | case NS_ooxml::LN_CT_TrPrBase_tblCellSpacing: | |||
367 | // To-Do: Not yet preserved | |||
368 | break; | |||
369 | case NS_ooxml::LN_CT_TblPrBase_tblCellSpacing: | |||
370 | // To-Do: Not yet preserved | |||
371 | break; | |||
372 | case NS_ooxml::LN_CT_TblPrBase_bidiVisual: | |||
373 | { | |||
374 | TablePropertyMapPtr pPropMap(new TablePropertyMap()); | |||
375 | pPropMap->Insert(PROP_WRITING_MODE, uno::makeAny(sal_Int16(nIntValue ? text::WritingMode2::RL_TB : text::WritingMode2::LR_TB))); | |||
376 | insertTableProps(pPropMap); | |||
377 | break; | |||
378 | } | |||
379 | default: | |||
380 | bRet = false; | |||
381 | ||||
382 | #ifdef DBG_UTIL | |||
383 | TagLogger::getInstance().element("unhandled"); | |||
384 | #endif | |||
385 | } | |||
386 | } | |||
387 | return bRet; | |||
388 | } | |||
389 | ||||
390 | DomainMapperTableManager::IntVectorPtr const & DomainMapperTableManager::getCurrentGrid( ) | |||
391 | { | |||
392 | return m_aTableGrid.back( ); | |||
393 | } | |||
394 | ||||
395 | DomainMapperTableManager::IntVectorPtr const & DomainMapperTableManager::getCurrentCellWidths( ) | |||
396 | { | |||
397 | return m_aCellWidths.back( ); | |||
398 | } | |||
399 | ||||
400 | uno::Sequence<beans::PropertyValue> DomainMapperTableManager::getCurrentTablePosition( ) | |||
401 | { | |||
402 | if ( !m_aTablePositions.empty( ) && m_aTablePositions.back() ) | |||
403 | return m_aTablePositions.back( )->getTablePosition(); | |||
404 | else | |||
405 | return uno::Sequence< beans::PropertyValue >(); | |||
406 | } | |||
407 | ||||
408 | TablePositionHandler* DomainMapperTableManager::getCurrentTableRealPosition() | |||
409 | { | |||
410 | if ( !m_aTablePositions.empty( ) && m_aTablePositions.back() ) | |||
411 | return m_aTablePositions.back().get(); | |||
412 | else | |||
413 | return nullptr; | |||
414 | } | |||
415 | ||||
416 | TableParagraphVectorPtr DomainMapperTableManager::getCurrentParagraphs( ) | |||
417 | { | |||
418 | return m_aParagraphsToEndTable.top( ); | |||
419 | } | |||
420 | ||||
421 | void DomainMapperTableManager::setIsInShape(bool bIsInShape) | |||
422 | { | |||
423 | m_bIsInShape = bIsInShape; | |||
424 | } | |||
425 | ||||
426 | void DomainMapperTableManager::startLevel( ) | |||
427 | { | |||
428 | TableManager::startLevel( ); | |||
429 | ||||
430 | // If requested, pop the value that was pushed too early. | |||
431 | std::optional<sal_Int32> oCurrentWidth; | |||
432 | if (m_bPushCurrentWidth && !m_aCellWidths.empty() && !m_aCellWidths.back()->empty()) | |||
433 | { | |||
434 | oCurrentWidth = m_aCellWidths.back()->back(); | |||
435 | m_aCellWidths.back()->pop_back(); | |||
436 | } | |||
437 | std::optional<TableParagraph> oParagraph; | |||
438 | if (getTableDepthDifference() > 0 && !m_aParagraphsToEndTable.empty() && !m_aParagraphsToEndTable.top()->empty()) | |||
439 | { | |||
440 | oParagraph = m_aParagraphsToEndTable.top()->back(); | |||
441 | m_aParagraphsToEndTable.top()->pop_back(); | |||
442 | } | |||
443 | ||||
444 | IntVectorPtr pNewGrid = std::make_shared<vector<sal_Int32>>(); | |||
445 | IntVectorPtr pNewCellWidths = std::make_shared<vector<sal_Int32>>(); | |||
446 | TablePositionHandlerPtr pNewPositionHandler; | |||
447 | m_aTableGrid.push_back( pNewGrid ); | |||
448 | m_aCellWidths.push_back( pNewCellWidths ); | |||
449 | m_aTablePositions.push_back( pNewPositionHandler ); | |||
450 | // empty name will be replaced by the table style name, if it exists | |||
451 | m_aTableStyleNames.push_back( OUString() ); | |||
452 | ||||
453 | TablePositionHandlerPtr pTmpPosition; | |||
454 | TablePropertyMapPtr pTmpProperties( new TablePropertyMap( ) ); | |||
455 | m_aTmpPosition.push_back( pTmpPosition ); | |||
456 | m_aTmpTableProperties.push_back( pTmpProperties ); | |||
457 | m_nCell.push_back( 0 ); | |||
458 | m_nTableWidth = 0; | |||
459 | m_nLayoutType = 0; | |||
460 | TableParagraphVectorPtr pNewParagraphs = std::make_shared<vector<TableParagraph>>(); | |||
461 | m_aParagraphsToEndTable.push( pNewParagraphs ); | |||
462 | ||||
463 | // And push it back to the right level. | |||
464 | if (oCurrentWidth) | |||
465 | m_aCellWidths.back()->push_back(*oCurrentWidth); | |||
466 | if (oParagraph) | |||
467 | m_aParagraphsToEndTable.top()->push_back(*oParagraph); | |||
468 | } | |||
469 | ||||
470 | void DomainMapperTableManager::endLevel( ) | |||
471 | { | |||
472 | if (m_aTableGrid.empty()) | |||
473 | { | |||
474 | SAL_WARN("writerfilter.dmapper", "Table stack is empty")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "writerfilter.dmapper")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "Table stack is empty" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper" ), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapperTableManager.cxx" ":" "474" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "Table stack is empty"), 0); } else { :: std::ostringstream sal_detail_stream; sal_detail_stream << "Table stack is empty"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapperTableManager.cxx" ":" "474" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "Table stack is empty") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapperTableManager.cxx" ":" "474" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "Table stack is empty"), 0); } else { :: std::ostringstream sal_detail_stream; sal_detail_stream << "Table stack is empty"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("writerfilter.dmapper"), ("/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapperTableManager.cxx" ":" "474" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
475 | return; | |||
476 | } | |||
477 | ||||
478 | m_aTableGrid.pop_back( ); | |||
479 | ||||
480 | // Do the same trick as in startLevel(): pop the value that was pushed too early. | |||
481 | std::optional<sal_Int32> oCurrentWidth; | |||
482 | if (m_bPushCurrentWidth && !m_aCellWidths.empty() && !m_aCellWidths.back()->empty()) | |||
483 | oCurrentWidth = m_aCellWidths.back()->back(); | |||
484 | m_aCellWidths.pop_back( ); | |||
485 | // And push it back to the right level. | |||
486 | if (oCurrentWidth && !m_aCellWidths.empty() && !m_aCellWidths.back()->empty()) | |||
487 | m_aCellWidths.back()->push_back(*oCurrentWidth); | |||
488 | ||||
489 | m_nCell.pop_back( ); | |||
490 | m_nTableWidth = 0; | |||
491 | m_nLayoutType = 0; | |||
492 | ||||
493 | m_aTmpPosition.pop_back( ); | |||
494 | m_aTmpTableProperties.pop_back( ); | |||
495 | ||||
496 | TableManager::endLevel( ); | |||
497 | #ifdef DBG_UTIL | |||
498 | TagLogger::getInstance().startElement("dmappertablemanager.endLevel"); | |||
499 | PropertyMapPtr pProps = getTableProps().get(); | |||
500 | if (pProps) | |||
501 | getTableProps()->dumpXml(); | |||
502 | ||||
503 | TagLogger::getInstance().endElement(); | |||
504 | #endif | |||
505 | ||||
506 | // Pop back the table position after endLevel as it's used | |||
507 | // in the endTable method called in endLevel. | |||
508 | m_aTablePositions.pop_back(); | |||
509 | m_aTableStyleNames.pop_back(); | |||
510 | m_aParagraphsToEndTable.pop(); | |||
511 | } | |||
512 | ||||
513 | void DomainMapperTableManager::endOfCellAction() | |||
514 | { | |||
515 | #ifdef DBG_UTIL | |||
516 | TagLogger::getInstance().element("endOFCellAction"); | |||
517 | #endif | |||
518 | ||||
519 | if ( !isInTable() ) | |||
520 | throw std::out_of_range("cell without a table"); | |||
521 | if ( m_nGridSpan > 1 ) | |||
522 | setCurrentGridSpan( m_nGridSpan ); | |||
523 | m_nGridSpan = 1; | |||
524 | ++m_nCell.back( ); | |||
525 | } | |||
526 | ||||
527 | bool DomainMapperTableManager::shouldInsertRow(IntVectorPtr pCellWidths, IntVectorPtr pTableGrid, size_t nGrids, bool& rIsIncompleteGrid) | |||
528 | { | |||
529 | if (pCellWidths->empty()) | |||
530 | return false; | |||
531 | if (m_nLayoutType == NS_ooxml::LN_Value_doc_ST_TblLayout_fixed) | |||
532 | return true; | |||
533 | if (pCellWidths->size() == nGrids) | |||
534 | return true; | |||
535 | rIsIncompleteGrid = true; | |||
536 | return nGrids > pTableGrid->size(); | |||
537 | } | |||
538 | ||||
539 | void DomainMapperTableManager::endOfRowAction() | |||
540 | { | |||
541 | #ifdef DBG_UTIL | |||
542 | TagLogger::getInstance().startElement("endOfRowAction"); | |||
543 | #endif | |||
544 | ||||
545 | // Compare the table position and style with the previous ones. We may need to split | |||
546 | // into two tables if those are different. We surely don't want to do anything | |||
547 | // if we don't have any row yet. | |||
548 | TablePositionHandlerPtr pTmpPosition = m_aTmpPosition.back(); | |||
549 | TablePropertyMapPtr pTablePropMap = m_aTmpTableProperties.back( ); | |||
550 | TablePositionHandlerPtr pCurrentPosition = m_aTablePositions.back(); | |||
551 | bool bSamePosition = ( pTmpPosition == pCurrentPosition ) || | |||
552 | ( pTmpPosition && pCurrentPosition && *pTmpPosition == *pCurrentPosition ); | |||
553 | bool bIsSetTableStyle = pTablePropMap->isSet(META_PROP_TABLE_STYLE_NAME); | |||
554 | OUString sTableStyleName; | |||
555 | bool bSameTableStyle = ( !bIsSetTableStyle && m_aTableStyleNames.back().isEmpty()) || | |||
556 | ( bIsSetTableStyle && | |||
557 | (pTablePropMap->getProperty(META_PROP_TABLE_STYLE_NAME)->second >>= sTableStyleName) && | |||
558 | sTableStyleName == m_aTableStyleNames.back() ); | |||
559 | if ( (!bSamePosition || !bSameTableStyle) && m_nRow > 0 ) | |||
560 | { | |||
561 | // Save the grid infos to have them survive the end/start level | |||
562 | IntVectorPtr pTmpTableGrid = m_aTableGrid.back(); | |||
563 | IntVectorPtr pTmpCellWidths = m_aCellWidths.back(); | |||
564 | sal_uInt32 nTmpCell = m_nCell.back(); | |||
565 | TableParagraphVectorPtr pTableParagraphs = getCurrentParagraphs(); | |||
566 | ||||
567 | // endLevel and startLevel are taking care of the non finished row | |||
568 | // to carry it over to the next table | |||
569 | setKeepUnfinishedRow( true ); | |||
570 | endLevel(); | |||
571 | setKeepUnfinishedRow( false ); | |||
572 | startLevel(); | |||
573 | ||||
574 | m_aTableGrid.pop_back(); | |||
575 | m_aCellWidths.pop_back(); | |||
576 | m_nCell.pop_back(); | |||
577 | m_aTableGrid.push_back(pTmpTableGrid); | |||
578 | m_aCellWidths.push_back(pTmpCellWidths); | |||
579 | m_nCell.push_back(nTmpCell); | |||
580 | m_aParagraphsToEndTable.pop( ); | |||
581 | m_aParagraphsToEndTable.push( pTableParagraphs ); | |||
582 | } | |||
583 | // save table style in the first row for comparison | |||
584 | if ( m_nRow == 0 && pTablePropMap->isSet(META_PROP_TABLE_STYLE_NAME) ) | |||
585 | { | |||
586 | pTablePropMap->getProperty(META_PROP_TABLE_STYLE_NAME)->second >>= sTableStyleName; | |||
587 | m_aTableStyleNames.pop_back(); | |||
588 | m_aTableStyleNames.push_back( sTableStyleName ); | |||
589 | } | |||
590 | ||||
591 | // Push the tmp position now that we compared it | |||
592 | m_aTablePositions.pop_back(); | |||
593 | m_aTablePositions.push_back( pTmpPosition ); | |||
594 | m_aTmpPosition.back().clear( ); | |||
595 | ||||
596 | ||||
597 | IntVectorPtr pTableGrid = getCurrentGrid( ); | |||
598 | IntVectorPtr pCellWidths = getCurrentCellWidths( ); | |||
599 | if(!m_nTableWidth && !pTableGrid->empty()) | |||
600 | { | |||
601 | #ifdef DBG_UTIL | |||
602 | TagLogger::getInstance().startElement("tableWidth"); | |||
603 | #endif | |||
604 | ||||
605 | for( const auto& rCell : *pTableGrid ) | |||
606 | { | |||
607 | #ifdef DBG_UTIL | |||
608 | TagLogger::getInstance().startElement("col"); | |||
609 | TagLogger::getInstance().attribute("width", rCell); | |||
610 | TagLogger::getInstance().endElement(); | |||
611 | #endif | |||
612 | ||||
613 | m_nTableWidth = o3tl::saturating_add(m_nTableWidth, rCell); | |||
614 | } | |||
615 | if (m_nTableWidth) | |||
616 | // convert sum of grid twip values to 1/100 mm with rounding up to avoid table width loss | |||
617 | m_nTableWidth = static_cast<sal_Int32>(ceil(ConversionHelper::convertTwipToMM100Double(m_nTableWidth))); | |||
618 | ||||
619 | if (m_nTableWidth > 0 && !m_bTableSizeTypeInserted) | |||
620 | { | |||
621 | TablePropertyMapPtr pPropMap( new TablePropertyMap ); | |||
622 | pPropMap->setValue( TablePropertyMap::TABLE_WIDTH, m_nTableWidth ); | |||
623 | insertTableProps(pPropMap); | |||
624 | } | |||
625 | ||||
626 | #ifdef DBG_UTIL | |||
627 | TagLogger::getInstance().endElement(); | |||
628 | #endif | |||
629 | } | |||
630 | ||||
631 | std::vector<sal_uInt32> rCurrentSpans = getCurrentGridSpans(); | |||
632 | ||||
633 | #ifdef DBG_UTIL | |||
634 | TagLogger::getInstance().startElement("gridSpans"); | |||
635 | { | |||
636 | for (const auto& rGridSpan : rCurrentSpans) | |||
637 | { | |||
638 | TagLogger::getInstance().startElement("gridSpan"); | |||
639 | TagLogger::getInstance().attribute("span", rGridSpan); | |||
640 | TagLogger::getInstance().endElement(); | |||
641 | } | |||
642 | } | |||
643 | TagLogger::getInstance().endElement(); | |||
644 | #endif | |||
645 | ||||
646 | //calculate number of used grids - it has to match the size of m_aTableGrid | |||
647 | size_t nGrids = std::accumulate(rCurrentSpans.begin(), rCurrentSpans.end(), sal::static_int_cast<size_t>(0)); | |||
648 | ||||
649 | // sj: the grid is having no units... it is containing only relative values. | |||
650 | // a table with a grid of "1:2:1" looks identical as if the table is having | |||
651 | // a grid of "20:40:20" and it doesn't have to do something with the tableWidth | |||
652 | // -> so we have get the sum of each grid entry for the fullWidthRelative: | |||
653 | int nFullWidthRelative = 0; | |||
654 | for (int i : (*pTableGrid)) | |||
655 | nFullWidthRelative = o3tl::saturating_add(nFullWidthRelative, i); | |||
656 | ||||
657 | bool bIsIncompleteGrid = false; | |||
658 | if( pTableGrid->size() == nGrids && m_nCell.back( ) > 0 ) | |||
659 | { | |||
660 | /* | |||
661 | * If table width property set earlier is smaller than the current table width, | |||
662 | * then replace the TABLE_WIDTH property, set earlier. | |||
663 | */ | |||
664 | sal_Int32 nTableWidth(0); | |||
665 | sal_Int32 nTableWidthType(text::SizeType::VARIABLE); | |||
666 | pTablePropMap->getValue(TablePropertyMap::TABLE_WIDTH, nTableWidth); | |||
667 | pTablePropMap->getValue(TablePropertyMap::TABLE_WIDTH_TYPE, nTableWidthType); | |||
668 | if ((nTableWidthType == text::SizeType::FIX) && (nTableWidth < m_nTableWidth)) | |||
669 | { | |||
670 | pTablePropMap->setValue(TablePropertyMap::TABLE_WIDTH, m_nTableWidth); | |||
671 | } | |||
672 | if (nTableWidthType == text::SizeType::VARIABLE ) | |||
673 | { | |||
674 | if(nTableWidth > 100 || nTableWidth <= 0) | |||
675 | { | |||
676 | if(getTableDepth() > 1 && !m_bTableSizeTypeInserted) | |||
677 | { | |||
678 | pTablePropMap->setValue(TablePropertyMap::TABLE_WIDTH, sal_Int32(100)); | |||
679 | pTablePropMap->setValue(TablePropertyMap::TABLE_WIDTH_TYPE, text::SizeType::VARIABLE); | |||
680 | } | |||
681 | else | |||
682 | { | |||
683 | pTablePropMap->setValue(TablePropertyMap::TABLE_WIDTH, m_nTableWidth); | |||
684 | pTablePropMap->setValue(TablePropertyMap::TABLE_WIDTH_TYPE, text::SizeType::FIX); | |||
685 | } | |||
686 | } | |||
687 | } | |||
688 | uno::Sequence< text::TableColumnSeparator > aSeparators( getCurrentGridBefore() + m_nCell.back() - 1 ); | |||
689 | text::TableColumnSeparator* pSeparators = aSeparators.getArray(); | |||
690 | double nLastRelPos = 0.0; | |||
691 | sal_uInt32 nBorderGridIndex = 0; | |||
692 | ||||
693 | size_t nWidthsBound = getCurrentGridBefore() + m_nCell.back() - 1; | |||
694 | if (nWidthsBound) | |||
695 | { | |||
696 | if (nFullWidthRelative == 0) | |||
697 | throw o3tl::divide_by_zero(); | |||
698 | ||||
699 | ::std::vector< sal_uInt32 >::const_iterator aSpansIter = rCurrentSpans.begin(); | |||
700 | for( size_t nBorder = 0; nBorder < nWidthsBound; ++nBorder ) | |||
701 | { | |||
702 | double fGridWidth = 0.; | |||
703 | for ( sal_Int32 nGridCount = *aSpansIter; nGridCount > 0; --nGridCount ) | |||
704 | fGridWidth += (*pTableGrid)[nBorderGridIndex++]; | |||
705 | ||||
706 | double nRelPos = (fGridWidth * 10000) / nFullWidthRelative; | |||
707 | ||||
708 | pSeparators[nBorder].Position = rtl::math::round(nRelPos + nLastRelPos); | |||
709 | pSeparators[nBorder].IsVisible = true; | |||
710 | nLastRelPos = nLastRelPos + nRelPos; | |||
711 | ++aSpansIter; | |||
712 | } | |||
713 | } | |||
714 | TablePropertyMapPtr pPropMap( new TablePropertyMap ); | |||
715 | pPropMap->Insert( PROP_TABLE_COLUMN_SEPARATORS, uno::makeAny( aSeparators ) ); | |||
716 | ||||
717 | #ifdef DBG_UTIL | |||
718 | TagLogger::getInstance().startElement("rowProperties"); | |||
719 | pPropMap->dumpXml(); | |||
720 | TagLogger::getInstance().endElement(); | |||
721 | #endif | |||
722 | insertRowProps(pPropMap); | |||
723 | } | |||
724 | else if (shouldInsertRow(pCellWidths, pTableGrid, nGrids, bIsIncompleteGrid)) | |||
725 | { | |||
726 | // If we're here, then the number of cells does not equal to the amount | |||
727 | // defined by the grid, even after taking care of | |||
728 | // gridSpan/gridBefore/gridAfter. Handle this by ignoring the grid and | |||
729 | // providing the separators based on the provided cell widths, as long | |||
730 | // as we have a fixed layout; | |||
731 | // On the other hand even if the layout is not fixed, but the cell widths | |||
732 | // provided equal the total number of cells, and there are no after/before cells | |||
733 | // then use the cell widths to calculate the column separators. | |||
734 | // Also handle autofit tables with incomplete grids, when rows can have | |||
735 | // different widths and last cells can be wider, than their values. | |||
736 | uno::Sequence< text::TableColumnSeparator > aSeparators(pCellWidths->size() - 1); | |||
737 | text::TableColumnSeparator* pSeparators = aSeparators.getArray(); | |||
738 | sal_Int16 nSum = 0; | |||
739 | sal_uInt32 nPos = 0; | |||
740 | ||||
741 | if (bIsIncompleteGrid) | |||
742 | nFullWidthRelative = 0; | |||
743 | ||||
744 | // Avoid divide by zero (if there's no grid, position using cell widths). | |||
745 | if( nFullWidthRelative == 0 ) | |||
746 | for (size_t i = 0; i < pCellWidths->size(); ++i) | |||
747 | nFullWidthRelative += (*pCellWidths)[i]; | |||
748 | ||||
749 | if (bIsIncompleteGrid) | |||
750 | { | |||
751 | /* | |||
752 | * If table width property set earlier is smaller than the current table row width, | |||
753 | * then replace the TABLE_WIDTH property, set earlier. | |||
754 | */ | |||
755 | sal_Int32 nFullWidth = static_cast<sal_Int32>(ceil(ConversionHelper::convertTwipToMM100Double(nFullWidthRelative))); | |||
756 | sal_Int32 nTableWidth(0); | |||
757 | sal_Int32 nTableWidthType(text::SizeType::VARIABLE); | |||
758 | pTablePropMap->getValue(TablePropertyMap::TABLE_WIDTH, nTableWidth); | |||
759 | pTablePropMap->getValue(TablePropertyMap::TABLE_WIDTH_TYPE, nTableWidthType); | |||
760 | if (nTableWidth < nFullWidth) | |||
761 | { | |||
762 | pTablePropMap->setValue(TablePropertyMap::TABLE_WIDTH, nFullWidth); | |||
763 | } | |||
764 | } | |||
765 | ||||
766 | size_t nWidthsBound = pCellWidths->size() - 1; | |||
767 | if (nWidthsBound) | |||
768 | { | |||
769 | if (nFullWidthRelative == 0) | |||
770 | throw o3tl::divide_by_zero(); | |||
771 | ||||
772 | // At incomplete table grids, last cell width can be smaller, than its final width. | |||
773 | // Correct it based on the last but one column width and their span values. | |||
774 | if ( bIsIncompleteGrid && rCurrentSpans.size()-1 == nWidthsBound ) | |||
775 | { | |||
776 | auto aSpansIter = std::next(rCurrentSpans.begin(), nWidthsBound - 1); | |||
777 | sal_Int32 nFixLastCellWidth = (*pCellWidths)[nWidthsBound-1] / *aSpansIter * *std::next(aSpansIter); | |||
778 | if (nFixLastCellWidth > (*pCellWidths)[nWidthsBound]) | |||
779 | nFullWidthRelative += nFixLastCellWidth - (*pCellWidths)[nWidthsBound]; | |||
780 | } | |||
781 | ||||
782 | for (size_t i = 0; i < nWidthsBound; ++i) | |||
783 | { | |||
784 | nSum += (*pCellWidths)[i]; | |||
785 | pSeparators[nPos].Position = (nSum * 10000) / nFullWidthRelative; // Relative position | |||
786 | pSeparators[nPos].IsVisible = true; | |||
787 | nPos++; | |||
788 | } | |||
789 | } | |||
790 | ||||
791 | TablePropertyMapPtr pPropMap( new TablePropertyMap ); | |||
792 | pPropMap->Insert( PROP_TABLE_COLUMN_SEPARATORS, uno::makeAny( aSeparators ) ); | |||
793 | #ifdef DBG_UTIL | |||
794 | TagLogger::getInstance().startElement("rowProperties"); | |||
795 | pPropMap->dumpXml(); | |||
796 | TagLogger::getInstance().endElement(); | |||
797 | #endif | |||
798 | insertRowProps(pPropMap); | |||
799 | } | |||
800 | ||||
801 | // Now that potentially opened table is closed, save the table properties | |||
802 | TableManager::insertTableProps(pTablePropMap); | |||
803 | ||||
804 | m_aTmpTableProperties.pop_back(); | |||
805 | TablePropertyMapPtr pEmptyTableProps( new TablePropertyMap() ); | |||
806 | m_aTmpTableProperties.push_back( pEmptyTableProps ); | |||
807 | ||||
808 | ++m_nRow; | |||
809 | m_nCell.back( ) = 0; | |||
810 | getCurrentGrid()->clear(); | |||
811 | pCellWidths->clear(); | |||
812 | ||||
813 | m_bTableSizeTypeInserted = false; | |||
814 | ||||
815 | #ifdef DBG_UTIL | |||
816 | TagLogger::getInstance().endElement(); | |||
817 | #endif | |||
818 | } | |||
819 | ||||
820 | void DomainMapperTableManager::clearData() | |||
821 | { | |||
822 | m_nRow = m_nHeaderRepeat = m_nTableWidth = m_nLayoutType = 0; | |||
823 | } | |||
824 | ||||
825 | } | |||
826 | ||||
827 | /* 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_WRITERFILTER_SOURCE_DMAPPER_DOMAINMAPPERTABLEMANAGER_HXX |
20 | #define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_DOMAINMAPPERTABLEMANAGER_HXX |
21 | |
22 | #include "TablePropertiesHandler.hxx" |
23 | #include "TablePositionHandler.hxx" |
24 | |
25 | #include "TableManager.hxx" |
26 | #include "PropertyMap.hxx" |
27 | #include <vector> |
28 | #include <memory> |
29 | #include <comphelper/sequenceashashmap.hxx> |
30 | |
31 | namespace writerfilter::dmapper { |
32 | |
33 | class DomainMapper; |
34 | |
35 | class DomainMapperTableManager : public TableManager |
36 | { |
37 | typedef std::shared_ptr< std::vector<sal_Int32> > IntVectorPtr; |
38 | |
39 | sal_uInt32 m_nRow; |
40 | ::std::vector< sal_uInt32 > m_nCell; |
41 | sal_uInt32 m_nGridSpan; |
42 | sal_Int32 m_nHeaderRepeat; //counter of repeated headers - if == -1 then the repeating stops |
43 | sal_Int32 m_nTableWidth; //might be set directly or has to be calculated from the column positions |
44 | /// Are we in a shape (text append stack is not empty) or in the body document? |
45 | bool m_bIsInShape; |
46 | std::vector< OUString > m_aTableStyleNames; |
47 | /// Grab-bag of table look attributes for preserving. |
48 | comphelper::SequenceAsHashMap m_aTableLook; |
49 | std::vector< TablePositionHandlerPtr > m_aTablePositions; |
50 | std::vector< TablePositionHandlerPtr > m_aTmpPosition; ///< Temporarily stores the position to compare it later |
51 | std::vector< TablePropertyMapPtr > m_aTmpTableProperties; ///< Temporarily stores the table properties until end of row |
52 | |
53 | ::std::vector< IntVectorPtr > m_aTableGrid; |
54 | /// If this is true, then we pushed a width before the next level started, and that should be carried over when starting the next level. |
55 | bool m_bPushCurrentWidth; |
56 | /// Individual table cell width values, used only in case the number of cells doesn't match the table grid. |
57 | ::std::vector< IntVectorPtr > m_aCellWidths; |
58 | /// Remember if table width was already set, when we lack a w:tblW, it should be set manually at the end. |
59 | bool m_bTableSizeTypeInserted; |
60 | /// Table layout algorithm, IOW if we should consider fixed column width or not. |
61 | sal_uInt32 m_nLayoutType; |
62 | /// Collected table paragraphs for table style handling |
63 | std::stack< TableParagraphVectorPtr > m_aParagraphsToEndTable; |
64 | |
65 | std::unique_ptr<TablePropertiesHandler> m_pTablePropsHandler; |
66 | PropertyMapPtr m_pStyleProps; |
67 | |
68 | bool shouldInsertRow(IntVectorPtr pCellWidths, IntVectorPtr pTableGrid, size_t nGrids, bool& rIsIncompleteGrid); |
69 | |
70 | virtual void clearData() override; |
71 | |
72 | public: |
73 | |
74 | DomainMapperTableManager(); |
75 | virtual ~DomainMapperTableManager() override; |
76 | |
77 | // use this method to avoid adding the properties for the table |
78 | // but in the provided properties map. |
79 | void SetStyleProperties( PropertyMapPtr pProperties ) { m_pStyleProps = pProperties; }; |
80 | |
81 | virtual bool sprm(Sprm & rSprm) override; |
82 | bool attribute(Id nName, Value const & val); |
83 | |
84 | virtual void startLevel( ) override; |
85 | virtual void endLevel( ) override; |
86 | |
87 | virtual void endOfCellAction() override; |
88 | virtual void endOfRowAction() override; |
89 | |
90 | IntVectorPtr const & getCurrentGrid( ); |
91 | IntVectorPtr const & getCurrentCellWidths( ); |
92 | TableParagraphVectorPtr getCurrentParagraphs( ); |
93 | |
94 | /// Turn the attributes collected so far in m_aTableLook into a property and clear the container. |
95 | void finishTableLook(); |
96 | css::uno::Sequence<css::beans::PropertyValue> getCurrentTablePosition(); |
97 | TablePositionHandler* getCurrentTableRealPosition(); |
98 | |
99 | virtual void cellProps(const TablePropertyMapPtr& pProps) override |
100 | { |
101 | if ( m_pStyleProps ) |
102 | m_pStyleProps->InsertProps(pProps.get()); |
103 | else |
104 | TableManager::cellProps( pProps ); |
105 | }; |
106 | |
107 | virtual void insertRowProps(const TablePropertyMapPtr& pProps) override |
108 | { |
109 | if ( m_pStyleProps ) |
110 | m_pStyleProps->InsertProps(pProps.get()); |
111 | else |
112 | TableManager::insertRowProps( pProps ); |
113 | }; |
114 | |
115 | virtual void insertTableProps(const TablePropertyMapPtr& pProps) override |
116 | { |
117 | if ( m_pStyleProps ) |
118 | m_pStyleProps->InsertProps(pProps.get()); |
119 | else |
120 | m_aTmpTableProperties.back()->InsertProps(pProps.get()); |
121 | }; |
122 | |
123 | void SetLayoutType(sal_uInt32 nLayoutType) |
124 | { |
125 | m_nLayoutType = nLayoutType; |
126 | } |
127 | |
128 | using TableManager::isInCell; |
129 | |
130 | void setIsInShape(bool bIsInShape); |
131 | |
132 | }; |
133 | |
134 | } |
135 | |
136 | #endif // INCLUDED_WRITERFILTER_SOURCE_DMAPPER_DOMAINMAPPERTABLEMANAGER_HXX |
137 | |
138 | /* 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: */ |