Bug Summary

File:home/maarten/src/libreoffice/core/include/tools/ref.hxx
Warning:line 56, column 30
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name DomainMapperTableManager.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/libxml2 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/oox/generated -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/writerfilter/source -I /home/maarten/src/libreoffice/core/writerfilter/inc -I /home/maarten/src/libreoffice/core/writerfilter/source -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapperTableManager.cxx

/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapperTableManager.cxx

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
34namespace writerfilter::dmapper {
35
36using namespace ::com::sun::star;
37using namespace ::std;
38
39DomainMapperTableManager::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
58DomainMapperTableManager::~DomainMapperTableManager()
59{
60}
61
62bool 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
101void DomainMapperTableManager::finishTableLook()
102{
103 TablePropertyMapPtr pPropMap(new TablePropertyMap());
1
Memory is allocated
104 pPropMap->Insert(META_PROP_TABLE_LOOK, uno::makeAny(m_aTableLook.getAsConstPropertyValueList()));
105 m_aTableLook.clear();
106 insertTableProps(pPropMap);
2
Calling 'DomainMapperTableManager::insertTableProps'
15
Returning; memory was released
107}
16
Calling '~SvRef'
108
109bool 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
390DomainMapperTableManager::IntVectorPtr const & DomainMapperTableManager::getCurrentGrid( )
391{
392 return m_aTableGrid.back( );
393}
394
395DomainMapperTableManager::IntVectorPtr const & DomainMapperTableManager::getCurrentCellWidths( )
396{
397 return m_aCellWidths.back( );
398}
399
400uno::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
408TablePositionHandler* DomainMapperTableManager::getCurrentTableRealPosition()
409{
410 if ( !m_aTablePositions.empty( ) && m_aTablePositions.back() )
411 return m_aTablePositions.back().get();
412 else
413 return nullptr;
414}
415
416TableParagraphVectorPtr DomainMapperTableManager::getCurrentParagraphs( )
417{
418 return m_aParagraphsToEndTable.top( );
419}
420
421void DomainMapperTableManager::setIsInShape(bool bIsInShape)
422{
423 m_bIsInShape = bIsInShape;
424}
425
426void 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
470void 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
513void 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
527bool 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
539void 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
820void 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: */

/home/maarten/src/libreoffice/core/writerfilter/source/dmapper/DomainMapperTableManager.hxx

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
31namespace writerfilter::dmapper {
32
33class DomainMapper;
34
35class 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
72public:
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 )
3
Taking true branch
118 m_pStyleProps->InsertProps(pProps.get());
4
Calling '~SvRef'
14
Returning from '~SvRef'
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: */

/home/maarten/src/libreoffice/core/include/tools/ref.hxx

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
31namespace tools {
32
33/** T must be a class that extends SvRefBase */
34template<typename T> class SAL_DLLPUBLIC_RTTI__attribute__ ((type_visibility("default"))) SvRef final {
35public:
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();
5
Taking true branch
6
Calling 'SvRefBase::ReleaseRef'
13
Returning; memory was released
17
Taking true branch
18
Use of memory after it is freed
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
104private:
105 T * pObj;
106};
107
108/**
109 * This implements similar functionality to std::make_shared.
110 */
111template<typename T, typename... Args>
112SvRef<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 */
120class 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
128protected:
129 virtual ~SvRefBase() COVERITY_NOEXCEPT_FALSE;
130
131public:
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__))
;
7
Assuming field 'nRefCount' is >= 1
8
'?' condition is true
157 if( --nRefCount == 0 && !bNoDelete)
9
Assuming the condition is true
10
Assuming field 'bNoDelete' is 0
11
Taking true branch
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;
12
Memory is released
164 }
165 }
166
167 unsigned int GetRefCount() const
168 { return nRefCount; }
169};
170
171template<typename T>
172class SvCompatWeakBase;
173
174/** SvCompatWeakHdl acts as an intermediary between SvCompatWeakRef<T> and T.
175*/
176template<typename T>
177class SvCompatWeakHdl final : public SvRefBase
178{
179 friend class SvCompatWeakBase<T>;
180 T* _pObj;
181
182 SvCompatWeakHdl( T* pObj ) : _pObj( pObj ) {}
183
184public:
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*/
192template<typename T>
193class SvCompatWeakBase
194{
195 tools::SvRef< SvCompatWeakHdl<T> > _xHdl;
196
197public:
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*/
210template<typename T>
211class SAL_WARN_UNUSED__attribute__((warn_unused)) SvCompatWeakRef
212{
213 tools::SvRef< SvCompatWeakHdl<T> > _xHdl;
214public:
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: */