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 "PropertyMap.hxx"
20 #include <ooxml/resourceids.hxx>
21 #include "DomainMapper_Impl.hxx"
22 #include "ConversionHelper.hxx"
23 #include <editeng/boxitem.hxx>
24 #include <i18nutil/paper.hxx>
25 #include <osl/diagnose.h>
26 #include <rtl/ustring.hxx>
27 #include <sal/log.hxx>
28 #include <com/sun/star/beans/PropertyAttribute.hpp>
29 #include <com/sun/star/beans/PropertyValue.hpp>
30 #include <com/sun/star/beans/XMultiPropertySet.hpp>
31 #include <com/sun/star/drawing/XDrawPageSupplier.hpp>
32 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
33 #include <com/sun/star/table/BorderLine2.hpp>
34 #include <com/sun/star/container/XEnumeration.hpp>
35 #include <com/sun/star/container/XEnumerationAccess.hpp>
36 #include <com/sun/star/container/XNameContainer.hpp>
37 #include <com/sun/star/style/BreakType.hpp>
38 #include <com/sun/star/style/PageStyleLayout.hpp>
39 #include <com/sun/star/style/XStyle.hpp>
40 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
41 #include <com/sun/star/table/ShadowFormat.hpp>
42 #include <com/sun/star/text/RelOrientation.hpp>
43 #include <com/sun/star/text/HoriOrientation.hpp>
44 #include <com/sun/star/text/HorizontalAdjust.hpp>
45 #include <com/sun/star/text/SizeType.hpp>
46 #include <com/sun/star/text/VertOrientation.hpp>
47 #include <com/sun/star/text/WritingMode.hpp>
48 #include <com/sun/star/text/WritingMode2.hpp>
49 #include <com/sun/star/text/XTextColumns.hpp>
50 #include <com/sun/star/text/XText.hpp>
51 #include <com/sun/star/text/TextGridMode.hpp>
52 #include <com/sun/star/text/XTextCopy.hpp>
53 #include <com/sun/star/style/VerticalAlignment.hpp>
54 #include <comphelper/sequence.hxx>
55 #include <comphelper/propertyvalue.hxx>
56 #include <tools/diagnose_ex.h>
57 #include "PropertyMapHelper.hxx"
58 #include <o3tl/sorted_vector.hxx>
59 
60 using namespace com::sun::star;
61 
62 namespace writerfilter {
63 namespace dmapper {
64 
GetPropertyValues(bool bCharGrabBag)65 uno::Sequence< beans::PropertyValue > PropertyMap::GetPropertyValues( bool bCharGrabBag )
66 {
67     using comphelper::makePropertyValue;
68 
69     if ( m_aValues.empty() && !m_vMap.empty() )
70     {
71         size_t nCharGrabBag = 0;
72         size_t nParaGrabBag = 0;
73         size_t nCellGrabBag = 0;
74         size_t nRowGrabBag  = 0;
75 
76         const PropValue* pParaStyleProp = nullptr;
77         const PropValue* pCharStyleProp = nullptr;
78         const PropValue* pNumRuleProp   = nullptr;
79 
80         for ( const auto& rPropPair : m_vMap )
81         {
82             if ( rPropPair.second.getGrabBagType() == CHAR_GRAB_BAG )
83                 nCharGrabBag++;
84             else if ( rPropPair.second.getGrabBagType() == PARA_GRAB_BAG )
85                 nParaGrabBag++;
86             else if ( rPropPair.second.getGrabBagType() == CELL_GRAB_BAG )
87                 nCellGrabBag++;
88             else if ( rPropPair.first == PROP_CELL_INTEROP_GRAB_BAG )
89             {
90                 uno::Sequence< beans::PropertyValue > aSeq;
91                 rPropPair.second.getValue() >>= aSeq;
92                 nCellGrabBag += aSeq.getLength();
93             }
94             else if ( rPropPair.second.getGrabBagType() == ROW_GRAB_BAG )
95                 nRowGrabBag++;
96 
97             if ( rPropPair.first == PROP_PARA_STYLE_NAME ) pParaStyleProp = &rPropPair.second;
98             if ( rPropPair.first == PROP_CHAR_STYLE_NAME ) pCharStyleProp = &rPropPair.second;
99             if ( rPropPair.first == PROP_NUMBERING_RULES ) pNumRuleProp   = &rPropPair.second;
100         }
101 
102         // Style names have to be the first elements within the property sequence
103         // otherwise they will overwrite 'hard' attributes
104         if ( pParaStyleProp != nullptr )
105             m_aValues.push_back( makePropertyValue( getPropertyName( PROP_PARA_STYLE_NAME ), pParaStyleProp->getValue() ) );
106         if ( pCharStyleProp != nullptr )
107             m_aValues.push_back( makePropertyValue( getPropertyName( PROP_CHAR_STYLE_NAME ), pCharStyleProp->getValue() ) );
108         if ( pNumRuleProp != nullptr )
109             m_aValues.push_back( makePropertyValue(getPropertyName( PROP_NUMBERING_RULES ), pNumRuleProp->getValue() ) );
110 
111         // If there are any grab bag properties, we need one slot for them.
112         uno::Sequence< beans::PropertyValue > aCharGrabBagValues( nCharGrabBag );
113         uno::Sequence< beans::PropertyValue > aParaGrabBagValues( nParaGrabBag );
114         uno::Sequence< beans::PropertyValue > aCellGrabBagValues( nCellGrabBag );
115         uno::Sequence< beans::PropertyValue > aRowGrabBagValues ( nRowGrabBag );
116         beans::PropertyValue* pCharGrabBagValues = aCharGrabBagValues.getArray();
117         beans::PropertyValue* pParaGrabBagValues = aParaGrabBagValues.getArray();
118         beans::PropertyValue* pCellGrabBagValues = aCellGrabBagValues.getArray();
119         beans::PropertyValue* pRowGrabBagValues  = aRowGrabBagValues.getArray();
120         // Record index for the next property to be added in each grab bag.
121         sal_Int32 nRowGrabBagValue  = 0;
122         sal_Int32 nCellGrabBagValue = 0;
123         sal_Int32 nParaGrabBagValue = 0;
124         sal_Int32 nCharGrabBagValue = 0;
125 
126         for ( const auto& rPropPair : m_vMap )
127         {
128             if ( rPropPair.first != PROP_PARA_STYLE_NAME &&
129                  rPropPair.first != PROP_CHAR_STYLE_NAME &&
130                  rPropPair.first != PROP_NUMBERING_RULES )
131             {
132                 if ( rPropPair.second.getGrabBagType() == CHAR_GRAB_BAG )
133                 {
134                     if ( bCharGrabBag )
135                     {
136                         pCharGrabBagValues[nCharGrabBagValue].Name  = getPropertyName( rPropPair.first );
137                         pCharGrabBagValues[nCharGrabBagValue].Value = rPropPair.second.getValue();
138                         ++nCharGrabBagValue;
139                     }
140                 }
141                 else if ( rPropPair.second.getGrabBagType() == PARA_GRAB_BAG )
142                 {
143                     pParaGrabBagValues[nParaGrabBagValue].Name  = getPropertyName( rPropPair.first );
144                     pParaGrabBagValues[nParaGrabBagValue].Value = rPropPair.second.getValue();
145                     ++nParaGrabBagValue;
146                 }
147                 else if ( rPropPair.second.getGrabBagType() == CELL_GRAB_BAG )
148                 {
149                     pCellGrabBagValues[nCellGrabBagValue].Name  = getPropertyName( rPropPair.first );
150                     pCellGrabBagValues[nCellGrabBagValue].Value = rPropPair.second.getValue();
151                     ++nCellGrabBagValue;
152                 }
153                 else if ( rPropPair.second.getGrabBagType() == ROW_GRAB_BAG )
154                 {
155                     pRowGrabBagValues[nRowGrabBagValue].Name  = getPropertyName( rPropPair.first );
156                     pRowGrabBagValues[nRowGrabBagValue].Value = rPropPair.second.getValue();
157                     ++nRowGrabBagValue;
158                 }
159                 else if ( rPropPair.first == PROP_CELL_INTEROP_GRAB_BAG )
160                 {
161                     uno::Sequence< beans::PropertyValue > aSeq;
162                     rPropPair.second.getValue() >>= aSeq;
163                     std::copy(aSeq.begin(), aSeq.end(), pCellGrabBagValues + nCellGrabBagValue);
164                     nCellGrabBagValue += aSeq.getLength();
165                 }
166                 else
167                 {
168                     m_aValues.push_back( makePropertyValue( getPropertyName( rPropPair.first ), rPropPair.second.getValue() ) );
169                 }
170             }
171         }
172 
173         if ( nCharGrabBag && bCharGrabBag )
174             m_aValues.push_back( makePropertyValue( "CharInteropGrabBag", uno::makeAny( aCharGrabBagValues ) ) );
175 
176         if ( nParaGrabBag )
177             m_aValues.push_back( makePropertyValue( "ParaInteropGrabBag", uno::makeAny( aParaGrabBagValues ) ) );
178 
179         if ( nCellGrabBag )
180             m_aValues.push_back( makePropertyValue( "CellInteropGrabBag", uno::makeAny( aCellGrabBagValues ) ) );
181 
182         if ( nRowGrabBag )
183             m_aValues.push_back( makePropertyValue( "RowInteropGrabBag", uno::makeAny( aRowGrabBagValues ) ) );
184     }
185 
186     return comphelper::containerToSequence( m_aValues );
187 }
188 
189 #ifdef DBG_UTIL
lcl_AnyToTag(const uno::Any & rAny)190 static void lcl_AnyToTag( const uno::Any& rAny )
191 {
192     try {
193         sal_Int32 aInt = 0;
194         if ( rAny >>= aInt )
195         {
196             TagLogger::getInstance().attribute( "value", rAny );
197         }
198         else
199         {
200             TagLogger::getInstance().attribute( "unsignedValue", 0 );
201         }
202 
203         sal_uInt32 auInt = 0;
204         rAny >>= auInt;
205         TagLogger::getInstance().attribute( "unsignedValue", auInt );
206 
207         float aFloat = 0.0f;
208         if ( rAny >>= aFloat )
209         {
210             TagLogger::getInstance().attribute( "floatValue", rAny );
211         }
212         else
213         {
214             TagLogger::getInstance().attribute( "unsignedValue", 0 );
215         }
216 
217         OUString aStr;
218         rAny >>= aStr;
219         TagLogger::getInstance().attribute( "stringValue", aStr );
220     }
221     catch ( ... )
222     {
223     }
224 }
225 #endif
226 
Insert(PropertyIds eId,const uno::Any & rAny,bool bOverwrite,GrabBagType i_GrabBagType)227 void PropertyMap::Insert( PropertyIds eId, const uno::Any& rAny, bool bOverwrite, GrabBagType i_GrabBagType )
228 {
229 #ifdef DBG_UTIL
230     const OUString& rInsert = getPropertyName(eId);
231 
232     TagLogger::getInstance().startElement("propertyMap.insert");
233     TagLogger::getInstance().attribute("name", rInsert);
234     lcl_AnyToTag(rAny);
235     TagLogger::getInstance().endElement();
236 #endif
237 
238     if ( !bOverwrite )
239         m_vMap.insert(std::make_pair(eId, PropValue(rAny, i_GrabBagType)));
240     else
241         m_vMap[eId] = PropValue(rAny, i_GrabBagType);
242 
243     Invalidate();
244 }
245 
Erase(PropertyIds eId)246 void PropertyMap::Erase( PropertyIds eId )
247 {
248     // Safe call to erase, it throws no exceptions, even if eId is not in m_vMap
249     m_vMap.erase(eId);
250 
251     Invalidate();
252 }
253 
getProperty(PropertyIds eId) const254 boost::optional< PropertyMap::Property > PropertyMap::getProperty( PropertyIds eId ) const
255 {
256     std::map< PropertyIds, PropValue >::const_iterator aIter = m_vMap.find( eId );
257     if ( aIter == m_vMap.end() )
258         return boost::optional<Property>();
259     else
260         return std::make_pair( eId, aIter->second.getValue() );
261 }
262 
isSet(PropertyIds eId) const263 bool PropertyMap::isSet( PropertyIds eId) const
264 {
265     return m_vMap.find( eId ) != m_vMap.end();
266 }
267 
268 #ifdef DBG_UTIL
dumpXml() const269 void PropertyMap::dumpXml() const
270 {
271     TagLogger::getInstance().startElement( "PropertyMap" );
272 
273     for ( const auto& rPropPair : m_vMap )
274     {
275         TagLogger::getInstance().startElement( "property" );
276 
277         TagLogger::getInstance().attribute( "name", getPropertyName( rPropPair.first ) );
278 
279         switch ( rPropPair.first )
280         {
281             case PROP_TABLE_COLUMN_SEPARATORS:
282                 lcl_DumpTableColumnSeparators( rPropPair.second.getValue() );
283                 break;
284             default:
285             {
286                 try
287                 {
288                     sal_Int32 aInt = 0;
289                     rPropPair.second.getValue() >>= aInt;
290                     TagLogger::getInstance().attribute( "value", aInt );
291 
292                     sal_uInt32 auInt = 0;
293                     rPropPair.second.getValue() >>= auInt;
294                     TagLogger::getInstance().attribute( "unsignedValue", auInt );
295 
296                     float aFloat = 0.0;
297                     rPropPair.second.getValue() >>= aFloat;
298                     TagLogger::getInstance().attribute( "floatValue", aFloat );
299 
300                     rPropPair.second.getValue() >>= auInt;
301                     TagLogger::getInstance().attribute( "stringValue", OUString() );
302                 }
303                 catch ( ... )
304                 {
305                 }
306             }
307             break;
308         }
309 
310         TagLogger::getInstance().endElement();
311     }
312 
313     TagLogger::getInstance().endElement();
314 }
315 #endif
316 
InsertProps(const PropertyMapPtr & rMap,const bool bOverwrite)317 void PropertyMap::InsertProps( const PropertyMapPtr& rMap, const bool bOverwrite )
318 {
319     if ( rMap )
320     {
321         for ( const auto& rPropPair : rMap->m_vMap )
322         {
323             if ( bOverwrite || !m_vMap.count(rPropPair.first) )
324                 m_vMap[rPropPair.first] = rPropPair.second;
325         }
326 
327         insertTableProperties( rMap.get(), bOverwrite );
328 
329         Invalidate();
330     }
331 }
332 
insertTableProperties(const PropertyMap *,const bool)333 void PropertyMap::insertTableProperties( const PropertyMap*, const bool )
334 {
335 #ifdef DBG_UTIL
336     TagLogger::getInstance().element( "PropertyMap.insertTableProperties" );
337 #endif
338 }
339 
printProperties()340 void PropertyMap::printProperties()
341 {
342 #ifdef DBG_UTIL
343     TagLogger::getInstance().startElement( "properties" );
344 
345     for ( const auto& rPropPair : m_vMap )
346     {
347         SAL_INFO( "writerfilter", getPropertyName( rPropPair.first ) );
348 
349         table::BorderLine2 aLine;
350         sal_Int32 nColor;
351         if ( rPropPair.second.getValue() >>= aLine )
352         {
353             TagLogger::getInstance().startElement( "borderline" );
354             TagLogger::getInstance().attribute( "color", aLine.Color );
355             TagLogger::getInstance().attribute( "inner", aLine.InnerLineWidth );
356             TagLogger::getInstance().attribute( "outer", aLine.OuterLineWidth );
357             TagLogger::getInstance().endElement();
358         }
359         else if ( rPropPair.second.getValue() >>= nColor )
360         {
361             TagLogger::getInstance().startElement( "color" );
362             TagLogger::getInstance().attribute( "number", nColor );
363             TagLogger::getInstance().endElement();
364         }
365     }
366 
367     TagLogger::getInstance().endElement();
368 #else
369     (void) this; // avoid loplugin:staticmethods
370 #endif
371 }
372 
SectionPropertyMap(bool bIsFirstSection)373 SectionPropertyMap::SectionPropertyMap( bool bIsFirstSection )
374     : m_bIsFirstSection( bIsFirstSection )
375     , m_eBorderApply( BorderApply::ToAllInSection )
376     , m_eBorderOffsetFrom( BorderOffsetFrom::Text )
377     , m_bTitlePage( false )
378     , m_nColumnCount( 0 )
379     , m_nColumnDistance( 1249 )
380     , m_bSeparatorLineIsOn( false )
381     , m_bEvenlySpaced( false )
382     , m_nPageNumber( -1 )
383     , m_nPageNumberType( -1 )
384     , m_nBreakType( -1 )
385     , m_nLeftMargin( 2540 )  // page left margin,  default 1 inch = 1440 twip -> 2540 1/100 mm
386     , m_nRightMargin( 2540 ) // page right margin,  default 1 inch = 1440 twip -> 2540 1/100 mm
387     , m_nTopMargin( 2540 )
388     , m_nBottomMargin( 2540 )
389     , m_nHeaderTop( 1270 )    // 720 twip
390     , m_nHeaderBottom( 1270 ) // 720 twip
391     , m_nGridType( 0 )
392     , m_nGridLinePitch( 1 )
393     , m_nDxtCharSpace( 0 )
394     , m_bGridSnapToChars( true )
395     , m_nLnnMod( 0 )
396     , m_nLnc(NS_ooxml::LN_Value_ST_LineNumberRestart_newPage)
397     , m_ndxaLnn( 0 )
398     , m_nLnnMin( 0 )
399     , m_bDefaultHeaderLinkToPrevious( true )
400     , m_bEvenPageHeaderLinkToPrevious( true )
401     , m_bFirstPageHeaderLinkToPrevious( true )
402     , m_bDefaultFooterLinkToPrevious( true )
403     , m_bEvenPageFooterLinkToPrevious( true )
404     , m_bFirstPageFooterLinkToPrevious( true )
405 {
406 #ifdef DBG_UTIL
407     static sal_Int32 nNumber = 0;
408     m_nDebugSectionNumber = nNumber++;
409 #endif
410 
411     for ( sal_Int32 nBorder = 0; nBorder < 4; ++nBorder )
412     {
413         m_nBorderDistances[nBorder] = -1;
414         m_bBorderShadows[nBorder] = false;
415     }
416     // todo: set defaults in ApplyPropertiesToPageStyles
417     // initialize defaults
418     PaperInfo aLetter( PAPER_LETTER );
419     // page height, 1/100mm
420     Insert( PROP_HEIGHT, uno::makeAny( static_cast<sal_Int32>(aLetter.getHeight()) ) );
421     // page width, 1/100mm
422     Insert( PROP_WIDTH, uno::makeAny( static_cast<sal_Int32>(aLetter.getWidth()) ) );
423     // page left margin, default 0x5a0 (1440) twip -> 2540 1/100 mm
424     Insert( PROP_LEFT_MARGIN, uno::makeAny( sal_Int32(2540) ) );
425     // page right margin, default 0x5a0 (1440) twip -> 2540 1/100 mm
426     Insert( PROP_RIGHT_MARGIN, uno::makeAny( sal_Int32(2540) ) );
427     // page top margin, default 0x5a0 (1440) twip -> 2540 1/100 mm
428     Insert( PROP_TOP_MARGIN, uno::makeAny( sal_Int32(2540) ) );
429     // page bottom margin, default 0x5a0 (1440) twip -> 2540 1/100 mm
430     Insert( PROP_BOTTOM_MARGIN, uno::makeAny( sal_Int32(2540) ) );
431     // page style layout
432     Insert( PROP_PAGE_STYLE_LAYOUT, uno::makeAny( style::PageStyleLayout_ALL ) );
433     uno::Any aFalse( uno::makeAny( false ) );
434     Insert( PROP_GRID_DISPLAY, aFalse );
435     Insert( PROP_GRID_PRINT, aFalse );
436     Insert( PROP_GRID_MODE, uno::makeAny( text::TextGridMode::NONE ) );
437 
438     if ( m_bIsFirstSection )
439     {
440         m_sFirstPageStyleName = getPropertyName( PROP_FIRST_PAGE );
441         m_sFollowPageStyleName = getPropertyName( PROP_STANDARD );
442     }
443 }
444 
GetPageStyle(DomainMapper_Impl & rDM_Impl,bool bFirst)445 uno::Reference< beans::XPropertySet > SectionPropertyMap::GetPageStyle( DomainMapper_Impl& rDM_Impl,
446                                                                         bool bFirst )
447 {
448     const uno::Reference< container::XNameContainer >& xPageStyles = rDM_Impl.GetPageStyles();
449     const uno::Reference < lang::XMultiServiceFactory >& xTextFactory = rDM_Impl.GetTextFactory();
450     uno::Reference< beans::XPropertySet > xRet;
451     try
452     {
453         if ( bFirst )
454         {
455             if ( m_sFirstPageStyleName.isEmpty() && xPageStyles.is() )
456             {
457                 m_sFirstPageStyleName = rDM_Impl.GetUnusedPageStyleName();
458                 m_aFirstPageStyle.set( xTextFactory->createInstance( "com.sun.star.style.PageStyle" ),
459                     uno::UNO_QUERY );
460 
461                 // Call insertByName() before GetPageStyle(), otherwise the
462                 // first and the follow page style will have the same name, and
463                 // insertByName() will fail.
464                 if ( xPageStyles.is() )
465                     xPageStyles->insertByName( m_sFirstPageStyleName, uno::makeAny( m_aFirstPageStyle ) );
466 
467                 // Ensure that m_aFollowPageStyle has been created
468                 GetPageStyle( rDM_Impl, false );
469                 // Chain m_aFollowPageStyle to be after m_aFirstPageStyle
470                 m_aFirstPageStyle->setPropertyValue( "FollowStyle",
471                     uno::makeAny( m_sFollowPageStyleName ) );
472             }
473             else if ( !m_aFirstPageStyle.is() && xPageStyles.is() )
474             {
475                 xPageStyles->getByName( m_sFirstPageStyleName ) >>= m_aFirstPageStyle;
476             }
477             xRet = m_aFirstPageStyle;
478         }
479         else
480         {
481             if ( m_sFollowPageStyleName.isEmpty() && xPageStyles.is() )
482             {
483                 m_sFollowPageStyleName = rDM_Impl.GetUnusedPageStyleName();
484                 m_aFollowPageStyle.set( xTextFactory->createInstance( "com.sun.star.style.PageStyle" ),
485                     uno::UNO_QUERY );
486                 xPageStyles->insertByName( m_sFollowPageStyleName, uno::makeAny( m_aFollowPageStyle ) );
487             }
488             else if ( !m_aFollowPageStyle.is() && xPageStyles.is() )
489             {
490                 xPageStyles->getByName( m_sFollowPageStyleName ) >>= m_aFollowPageStyle;
491             }
492             xRet = m_aFollowPageStyle;
493         }
494 
495     }
496     catch ( const uno::Exception& )
497     {
498         DBG_UNHANDLED_EXCEPTION( "writerfilter" );
499     }
500 
501     return xRet;
502 }
503 
SetBorder(BorderPosition ePos,sal_Int32 nLineDistance,const table::BorderLine2 & rBorderLine,bool bShadow)504 void SectionPropertyMap::SetBorder( BorderPosition ePos, sal_Int32 nLineDistance, const table::BorderLine2& rBorderLine, bool bShadow )
505 {
506     m_oBorderLines[ePos]     = rBorderLine;
507     m_nBorderDistances[ePos] = nLineDistance;
508     m_bBorderShadows[ePos]   = bShadow;
509 }
510 
ApplyBorderToPageStyles(DomainMapper_Impl & rDM_Impl,BorderApply eBorderApply,BorderOffsetFrom eOffsetFrom)511 void SectionPropertyMap::ApplyBorderToPageStyles( DomainMapper_Impl& rDM_Impl,
512                                                   BorderApply eBorderApply, BorderOffsetFrom eOffsetFrom )
513 {
514     /*
515     page border applies to:
516     nIntValue & 0x07 ->
517     0 all pages in this section
518     1 first page in this section
519     2 all pages in this section but first
520     3 whole document (all sections)
521     nIntValue & 0x18 -> page border depth 0 - in front 1- in back
522     nIntValue & 0xe0 ->
523     page border offset from:
524     0 offset from text
525     1 offset from edge of page
526     */
527     uno::Reference< beans::XPropertySet > xFirst;
528     uno::Reference< beans::XPropertySet > xSecond;
529     // todo: negative spacing (from ww8par6.cxx)
530     switch ( eBorderApply )
531     {
532         case BorderApply::ToAllInSection: // all styles
533             if ( !m_sFollowPageStyleName.isEmpty() )
534                 xFirst = GetPageStyle( rDM_Impl, false );
535             if ( !m_sFirstPageStyleName.isEmpty() )
536                 xSecond = GetPageStyle( rDM_Impl, true );
537             break;
538         case BorderApply::ToFirstPageInSection: // first page
539             if ( !m_sFirstPageStyleName.isEmpty() )
540                 xFirst = GetPageStyle( rDM_Impl, true );
541             break;
542         case BorderApply::ToAllButFirstInSection: // left and right
543             if ( !m_sFollowPageStyleName.isEmpty() )
544                 xFirst = GetPageStyle( rDM_Impl, false );
545             break;
546         default:
547             return;
548     }
549 
550     // has to be sorted like enum BorderPosition: l-r-t-b
551     const PropertyIds aBorderIds[4] =
552     {
553         PROP_LEFT_BORDER,
554         PROP_RIGHT_BORDER,
555         PROP_TOP_BORDER,
556         PROP_BOTTOM_BORDER
557     };
558 
559     const PropertyIds aBorderDistanceIds[4] =
560     {
561         PROP_LEFT_BORDER_DISTANCE,
562         PROP_RIGHT_BORDER_DISTANCE,
563         PROP_TOP_BORDER_DISTANCE,
564         PROP_BOTTOM_BORDER_DISTANCE
565     };
566 
567     const PropertyIds aMarginIds[4] =
568     {
569         PROP_LEFT_MARGIN,
570         PROP_RIGHT_MARGIN,
571         PROP_TOP_MARGIN,
572         PROP_BOTTOM_MARGIN
573     };
574 
575     for ( sal_Int32 nBorder = 0; nBorder < 4; ++nBorder )
576     {
577         if ( m_oBorderLines[nBorder] )
578         {
579             const OUString sBorderName = getPropertyName( aBorderIds[nBorder] );
580             if ( xFirst.is() )
581                 xFirst->setPropertyValue( sBorderName, uno::makeAny( *m_oBorderLines[nBorder] ) );
582             if ( xSecond.is() )
583                 xSecond->setPropertyValue( sBorderName, uno::makeAny( *m_oBorderLines[nBorder] ) );
584         }
585         if ( m_nBorderDistances[nBorder] >= 0 )
586         {
587             sal_uInt32 nLineWidth = 0;
588             if ( m_oBorderLines[nBorder] )
589                 nLineWidth = m_oBorderLines[nBorder]->LineWidth;
590             if ( xFirst.is() )
591                 SetBorderDistance( xFirst, aMarginIds[nBorder], aBorderDistanceIds[nBorder],
592                     m_nBorderDistances[nBorder], eOffsetFrom, nLineWidth );
593             if ( xSecond.is() )
594                 SetBorderDistance( xSecond, aMarginIds[nBorder], aBorderDistanceIds[nBorder],
595                     m_nBorderDistances[nBorder], eOffsetFrom, nLineWidth );
596         }
597     }
598 
599     if ( m_bBorderShadows[BORDER_RIGHT] )
600     {
601         table::ShadowFormat aFormat = getShadowFromBorder( *m_oBorderLines[BORDER_RIGHT] );
602         if ( xFirst.is() )
603             xFirst->setPropertyValue( getPropertyName( PROP_SHADOW_FORMAT ), uno::makeAny( aFormat ) );
604         if ( xSecond.is() )
605             xSecond->setPropertyValue( getPropertyName( PROP_SHADOW_FORMAT ), uno::makeAny( aFormat ) );
606     }
607 }
608 
getShadowFromBorder(const table::BorderLine2 & rBorder)609 table::ShadowFormat PropertyMap::getShadowFromBorder( const table::BorderLine2& rBorder )
610 {
611     // In Word UI, shadow is a boolean property, in OOXML, it's a boolean
612     // property of each 4 border type, finally in Writer the border is a
613     // property of the page style, with shadow location, distance and
614     // color. See SwWW8ImplReader::SetShadow().
615     table::ShadowFormat aFormat;
616     aFormat.Color       = sal_Int32(COL_BLACK);
617     aFormat.Location    = table::ShadowLocation_BOTTOM_RIGHT;
618     aFormat.ShadowWidth = rBorder.LineWidth;
619     return aFormat;
620 }
621 
SetBorderDistance(const uno::Reference<beans::XPropertySet> & xStyle,PropertyIds eMarginId,PropertyIds eDistId,sal_Int32 nDistance,BorderOffsetFrom eOffsetFrom,sal_uInt32 nLineWidth)622 void SectionPropertyMap::SetBorderDistance( const uno::Reference< beans::XPropertySet >& xStyle,
623                                             PropertyIds eMarginId,
624                                             PropertyIds eDistId,
625                                             sal_Int32 nDistance,
626                                             BorderOffsetFrom eOffsetFrom,
627                                             sal_uInt32 nLineWidth )
628 {
629     if (!xStyle.is())
630         return;
631     const OUString sMarginName = getPropertyName( eMarginId );
632     const OUString sBorderDistanceName = getPropertyName( eDistId );
633     uno::Any aMargin = xStyle->getPropertyValue( sMarginName );
634     sal_Int32 nMargin = 0;
635     aMargin >>= nMargin;
636     editeng::BorderDistanceFromWord(eOffsetFrom == BorderOffsetFrom::Edge, nMargin, nDistance,
637                                     nLineWidth);
638 
639     // Change the margins with the border distance
640     uno::Reference< beans::XMultiPropertySet > xMultiSet( xStyle, uno::UNO_QUERY_THROW );
641     uno::Sequence<OUString> aProperties { sMarginName, sBorderDistanceName };
642     uno::Sequence<uno::Any> aValues { uno::makeAny( nMargin ), uno::makeAny( nDistance ) };
643     xMultiSet->setPropertyValues( aProperties, aValues );
644 }
645 
DontBalanceTextColumns()646 void SectionPropertyMap::DontBalanceTextColumns()
647 {
648     try
649     {
650         if ( m_xColumnContainer.is() )
651             m_xColumnContainer->setPropertyValue( "DontBalanceTextColumns", uno::makeAny( true ) );
652     }
653     catch ( const uno::Exception& )
654     {
655         OSL_FAIL( "Exception in SectionPropertyMap::DontBalanceTextColumns" );
656     }
657 }
658 
ApplySectionProperties(const uno::Reference<beans::XPropertySet> & xSection,DomainMapper_Impl &)659 void SectionPropertyMap::ApplySectionProperties( const uno::Reference< beans::XPropertySet >& xSection, DomainMapper_Impl& /*rDM_Impl*/ )
660 {
661     try
662     {
663         if ( xSection.is() )
664         {
665             boost::optional< PropertyMap::Property > pProp = getProperty( PROP_WRITING_MODE );
666             if ( pProp )
667                 xSection->setPropertyValue( "WritingMode", pProp->second );
668         }
669     }
670     catch ( uno::Exception& )
671     {
672         DBG_UNHANDLED_EXCEPTION("writerfilter", "Exception in SectionPropertyMap::ApplySectionProperties");
673     }
674 }
675 
ApplyProtectionProperties(uno::Reference<beans::XPropertySet> & xSection,DomainMapper_Impl & rDM_Impl)676 void SectionPropertyMap::ApplyProtectionProperties( uno::Reference< beans::XPropertySet >& xSection, DomainMapper_Impl& rDM_Impl )
677 {
678     try
679     {
680         // Word implements section protection differently than LO.
681         // PROP_IS_PROTECTED only applies if global setting GetProtectForm is enabled.
682         bool bIsProtected = rDM_Impl.GetSettingsTable()->GetProtectForm();
683         if ( bIsProtected )
684         {
685             // If form protection is enabled then section protection is enabled, unless explicitly disabled
686             if ( isSet(PROP_IS_PROTECTED) )
687                 getProperty(PROP_IS_PROTECTED)->second >>= bIsProtected;
688             if ( !xSection.is() )
689                 xSection = rDM_Impl.appendTextSectionAfter( m_xStartingRange );
690             if ( xSection.is() )
691                 xSection->setPropertyValue( getPropertyName(PROP_IS_PROTECTED), uno::makeAny(bIsProtected) );
692         }
693     }
694     catch ( uno::Exception& )
695     {
696         DBG_UNHANDLED_EXCEPTION("writerfilter", "ApplyProtectionProperties failed setting PROP_IS_PROTECTED");
697     }
698 }
699 
ApplyColumnProperties(const uno::Reference<beans::XPropertySet> & xColumnContainer,DomainMapper_Impl & rDM_Impl)700 uno::Reference< text::XTextColumns > SectionPropertyMap::ApplyColumnProperties( const uno::Reference< beans::XPropertySet >& xColumnContainer,
701                                                                                 DomainMapper_Impl& rDM_Impl )
702 {
703     uno::Reference< text::XTextColumns > xColumns;
704     try
705     {
706         const OUString sTextColumns = getPropertyName( PROP_TEXT_COLUMNS );
707         if ( xColumnContainer.is() )
708             xColumnContainer->getPropertyValue( sTextColumns ) >>= xColumns;
709         uno::Reference< beans::XPropertySet > xColumnPropSet( xColumns, uno::UNO_QUERY_THROW );
710         if ( !m_bEvenlySpaced &&
711              ( sal_Int32(m_aColWidth.size()) == (m_nColumnCount + 1) ) &&
712              ( (sal_Int32(m_aColDistance.size()) == m_nColumnCount) || (sal_Int32(m_aColDistance.size()) == m_nColumnCount + 1) ) )
713         {
714             // the column width in word is an absolute value, in OOo it's relative
715             // the distances are both absolute
716             sal_Int32 nColSum = 0;
717             for ( sal_Int32 nCol = 0; nCol <= m_nColumnCount; ++nCol )
718             {
719                 nColSum += m_aColWidth[nCol];
720                 if ( nCol )
721                     nColSum += m_aColDistance[nCol - 1];
722             }
723 
724             sal_Int32 nRefValue = xColumns->getReferenceValue();
725             double fRel = nColSum ? double( nRefValue ) / double( nColSum ) : 0.0;
726             uno::Sequence< text::TextColumn > aColumns( m_nColumnCount + 1 );
727             text::TextColumn* pColumn = aColumns.getArray();
728 
729             nColSum = 0;
730             for ( sal_Int32 nCol = 0; nCol <= m_nColumnCount; ++nCol )
731             {
732                 const double fLeft = nCol ? m_aColDistance[nCol - 1] / 2 : 0;
733                 pColumn[nCol].LeftMargin = fLeft;
734                 const double fRight = nCol == m_nColumnCount ? 0 : m_aColDistance[nCol] / 2;
735                 pColumn[nCol].RightMargin = fRight;
736                 const double fWidth = m_aColWidth[nCol];
737                 pColumn[nCol].Width = (fWidth + fLeft + fRight) * fRel;
738                 nColSum += pColumn[nCol].Width;
739             }
740             if ( nColSum != nRefValue )
741                 pColumn[m_nColumnCount].Width += (nRefValue - nColSum);
742             assert( pColumn[m_nColumnCount].Width >= 0 );
743 
744             xColumns->setColumns( aColumns );
745         }
746         else
747         {
748             xColumns->setColumnCount( m_nColumnCount + 1 );
749             xColumnPropSet->setPropertyValue( getPropertyName( PROP_AUTOMATIC_DISTANCE ), uno::makeAny( m_nColumnDistance ) );
750         }
751 
752         if ( m_bSeparatorLineIsOn )
753         {
754             xColumnPropSet->setPropertyValue( "SeparatorLineIsOn", uno::makeAny( true ) );
755             xColumnPropSet->setPropertyValue( "SeparatorLineVerticalAlignment", uno::makeAny( style::VerticalAlignment_TOP ) );
756             xColumnPropSet->setPropertyValue( "SeparatorLineRelativeHeight", uno::makeAny( static_cast<sal_Int8>(100) ) );
757             xColumnPropSet->setPropertyValue( "SeparatorLineColor", uno::makeAny( static_cast<sal_Int32>(COL_BLACK) ) );
758             // 1 twip -> 2 mm100.
759             xColumnPropSet->setPropertyValue( "SeparatorLineWidth", uno::makeAny( static_cast<sal_Int32>(2) ) );
760         }
761         xColumnContainer->setPropertyValue( sTextColumns, uno::makeAny( xColumns ) );
762         // Set the columns to be unbalanced if that compatibility option is set or this is the last section.
763         m_xColumnContainer = xColumnContainer;
764         if ( rDM_Impl.GetSettingsTable()->GetNoColumnBalance() || rDM_Impl.GetIsLastSectionGroup() )
765             DontBalanceTextColumns();
766     }
767     catch ( const uno::Exception& )
768     {
769         OSL_FAIL( "Exception in SectionPropertyMap::ApplyColumnProperties" );
770     }
771     return xColumns;
772 }
773 
HasHeader(bool bFirstPage) const774 bool SectionPropertyMap::HasHeader( bool bFirstPage ) const
775 {
776     bool bRet = false;
777     if ( (bFirstPage && m_aFirstPageStyle.is()) || (!bFirstPage && m_aFollowPageStyle.is()) )
778     {
779         if ( bFirstPage )
780             m_aFirstPageStyle->getPropertyValue(
781                 getPropertyName( PROP_HEADER_IS_ON ) ) >>= bRet;
782         else
783             m_aFollowPageStyle->getPropertyValue(
784                 getPropertyName( PROP_HEADER_IS_ON ) ) >>= bRet;
785     }
786     return bRet;
787 }
788 
HasFooter(bool bFirstPage) const789 bool SectionPropertyMap::HasFooter( bool bFirstPage ) const
790 {
791     bool bRet = false;
792     if ( (bFirstPage && m_aFirstPageStyle.is()) || (!bFirstPage && m_aFollowPageStyle.is()) )
793     {
794         if ( bFirstPage )
795             m_aFirstPageStyle->getPropertyValue( getPropertyName( PROP_FOOTER_IS_ON ) ) >>= bRet;
796         else
797             m_aFollowPageStyle->getPropertyValue( getPropertyName( PROP_FOOTER_IS_ON ) ) >>= bRet;
798     }
799     return bRet;
800 }
801 
802 #define MIN_HEAD_FOOT_HEIGHT 100 // minimum header/footer height
803 
CopyHeaderFooterTextProperty(const uno::Reference<beans::XPropertySet> & xPrevStyle,const uno::Reference<beans::XPropertySet> & xStyle,PropertyIds ePropId)804 void SectionPropertyMap::CopyHeaderFooterTextProperty( const uno::Reference< beans::XPropertySet >& xPrevStyle,
805                                                        const uno::Reference< beans::XPropertySet >& xStyle,
806                                                        PropertyIds ePropId )
807 {
808     try {
809         OUString sName = getPropertyName( ePropId );
810 
811         SAL_INFO( "writerfilter", "Copying " << sName );
812         uno::Reference< text::XTextCopy > xTxt;
813         if ( xStyle.is() )
814             xTxt.set( xStyle->getPropertyValue( sName ), uno::UNO_QUERY_THROW );
815 
816         uno::Reference< text::XTextCopy > xPrevTxt;
817         if ( xPrevStyle.is() )
818             xPrevTxt.set( xPrevStyle->getPropertyValue( sName ), uno::UNO_QUERY_THROW );
819 
820         xTxt->copyText( xPrevTxt );
821     }
822     catch ( const uno::Exception& )
823     {
824         TOOLS_INFO_EXCEPTION( "writerfilter", "An exception occurred in SectionPropertyMap::CopyHeaderFooterTextProperty( )" );
825     }
826 }
827 
828 // Copy headers and footers from the previous page style.
CopyHeaderFooter(const uno::Reference<beans::XPropertySet> & xPrevStyle,const uno::Reference<beans::XPropertySet> & xStyle,bool bOmitRightHeader,bool bOmitLeftHeader,bool bOmitRightFooter,bool bOmitLeftFooter)829 void SectionPropertyMap::CopyHeaderFooter( const uno::Reference< beans::XPropertySet >& xPrevStyle,
830                                            const uno::Reference< beans::XPropertySet >& xStyle,
831                                            bool bOmitRightHeader,
832                                            bool bOmitLeftHeader,
833                                            bool bOmitRightFooter,
834                                            bool bOmitLeftFooter )
835 {
836     bool bHasPrevHeader = false;
837     bool bHeaderIsShared = true;
838     OUString sHeaderIsOn = getPropertyName( PROP_HEADER_IS_ON );
839     OUString sHeaderIsShared = getPropertyName( PROP_HEADER_IS_SHARED );
840     if ( xPrevStyle.is() )
841     {
842         xPrevStyle->getPropertyValue( sHeaderIsOn ) >>= bHasPrevHeader;
843         xPrevStyle->getPropertyValue( sHeaderIsShared ) >>= bHeaderIsShared;
844     }
845 
846     if ( bHasPrevHeader )
847     {
848         uno::Reference< beans::XMultiPropertySet > xMultiSet( xStyle, uno::UNO_QUERY_THROW );
849         uno::Sequence<OUString> aProperties { sHeaderIsOn, sHeaderIsShared };
850         uno::Sequence<uno::Any> aValues { uno::makeAny( true ), uno::makeAny( bHeaderIsShared ) };
851         xMultiSet->setPropertyValues( aProperties, aValues );
852         if ( !bOmitRightHeader )
853         {
854             CopyHeaderFooterTextProperty( xPrevStyle, xStyle,
855                 PROP_HEADER_TEXT );
856         }
857         if ( !bHeaderIsShared && !bOmitLeftHeader )
858         {
859             CopyHeaderFooterTextProperty( xPrevStyle, xStyle,
860                 PROP_HEADER_TEXT_LEFT );
861         }
862     }
863 
864     bool bHasPrevFooter = false;
865     bool bFooterIsShared = true;
866     OUString sFooterIsOn = getPropertyName( PROP_FOOTER_IS_ON );
867     OUString sFooterIsShared = getPropertyName( PROP_FOOTER_IS_SHARED );
868     if ( xPrevStyle.is() )
869     {
870         xPrevStyle->getPropertyValue( sFooterIsOn ) >>= bHasPrevFooter;
871         xPrevStyle->getPropertyValue( sFooterIsShared ) >>= bFooterIsShared;
872     }
873 
874     if ( bHasPrevFooter )
875     {
876         uno::Reference< beans::XMultiPropertySet > xMultiSet( xStyle, uno::UNO_QUERY_THROW );
877         uno::Sequence<OUString> aProperties { sFooterIsOn, sFooterIsShared };
878         uno::Sequence<uno::Any> aValues { uno::makeAny( true ), uno::makeAny( bFooterIsShared ) };
879         xMultiSet->setPropertyValues( aProperties, aValues );
880         if ( !bOmitRightFooter )
881         {
882             CopyHeaderFooterTextProperty( xPrevStyle, xStyle,
883                 PROP_FOOTER_TEXT );
884         }
885         if ( !bFooterIsShared && !bOmitLeftFooter )
886         {
887             CopyHeaderFooterTextProperty( xPrevStyle, xStyle,
888                 PROP_FOOTER_TEXT_LEFT );
889         }
890     }
891 }
892 
893 // Copy header and footer content from the previous docx section as needed.
894 //
895 // Any headers and footers which were not defined in this docx section
896 // should be "linked" with the corresponding header or footer from the
897 // previous section.  LO does not support linking of header/footer content
898 // across page styles so we just copy the content from the previous section.
CopyLastHeaderFooter(bool bFirstPage,DomainMapper_Impl & rDM_Impl)899 void SectionPropertyMap::CopyLastHeaderFooter( bool bFirstPage, DomainMapper_Impl& rDM_Impl )
900 {
901     SAL_INFO( "writerfilter", "START>>> SectionPropertyMap::CopyLastHeaderFooter()" );
902     SectionPropertyMap* pLastContext = rDM_Impl.GetLastSectionContext();
903     if ( pLastContext )
904     {
905         uno::Reference< beans::XPropertySet > xPrevStyle = pLastContext->GetPageStyle( rDM_Impl,
906             bFirstPage );
907         uno::Reference< beans::XPropertySet > xStyle = GetPageStyle( rDM_Impl,
908             bFirstPage );
909 
910         if ( bFirstPage )
911         {
912             CopyHeaderFooter( xPrevStyle, xStyle,
913                 !m_bFirstPageHeaderLinkToPrevious, true,
914                 !m_bFirstPageFooterLinkToPrevious, true );
915         }
916         else
917         {
918             CopyHeaderFooter( xPrevStyle, xStyle,
919                 !m_bDefaultHeaderLinkToPrevious,
920                 !m_bEvenPageHeaderLinkToPrevious,
921                 !m_bDefaultFooterLinkToPrevious,
922                 !m_bEvenPageFooterLinkToPrevious );
923         }
924     }
925     SAL_INFO( "writerfilter", "END>>> SectionPropertyMap::CopyLastHeaderFooter()" );
926 }
927 
PrepareHeaderFooterProperties(bool bFirstPage)928 void SectionPropertyMap::PrepareHeaderFooterProperties( bool bFirstPage )
929 {
930     bool bCopyFirstToFollow = bFirstPage && m_bTitlePage && m_aFollowPageStyle.is();
931 
932     sal_Int32 nTopMargin = m_nTopMargin;
933     sal_Int32 nHeaderTop = m_nHeaderTop;
934     if ( HasHeader( bFirstPage ) )
935     {
936         nTopMargin = nHeaderTop;
937         if ( m_nTopMargin > 0 && m_nTopMargin > nHeaderTop )
938             nHeaderTop = m_nTopMargin - nHeaderTop;
939         else
940             nHeaderTop = 0;
941 
942         // minimum header height 1mm
943         if ( nHeaderTop < MIN_HEAD_FOOT_HEIGHT )
944             nHeaderTop = MIN_HEAD_FOOT_HEIGHT;
945     }
946 
947 
948     if ( m_nTopMargin >= 0 ) //fixed height header -> see WW8Par6.hxx
949     {
950         Insert( PROP_HEADER_IS_DYNAMIC_HEIGHT, uno::makeAny( true ) );
951         Insert( PROP_HEADER_DYNAMIC_SPACING, uno::makeAny( true ) );
952         Insert( PROP_HEADER_BODY_DISTANCE, uno::makeAny( nHeaderTop - MIN_HEAD_FOOT_HEIGHT ) );// ULSpace.Top()
953         Insert( PROP_HEADER_HEIGHT, uno::makeAny( nHeaderTop ) );
954 
955         if (bCopyFirstToFollow && HasHeader(/*bFirstPage=*/true))
956         {
957             m_aFollowPageStyle->setPropertyValue("HeaderDynamicSpacing",
958                                                  getProperty(PROP_HEADER_DYNAMIC_SPACING)->second);
959             m_aFollowPageStyle->setPropertyValue("HeaderHeight",
960                                                  getProperty(PROP_HEADER_HEIGHT)->second);
961         }
962     }
963     else
964     {
965         //todo: old filter fakes a frame into the header/footer to support overlapping
966         //current setting is completely wrong!
967         Insert( PROP_HEADER_HEIGHT, uno::makeAny( nHeaderTop ) );
968         Insert( PROP_HEADER_BODY_DISTANCE, uno::makeAny( m_nTopMargin - nHeaderTop ) );
969         Insert( PROP_HEADER_IS_DYNAMIC_HEIGHT, uno::makeAny( false ) );
970         Insert( PROP_HEADER_DYNAMIC_SPACING, uno::makeAny( false ) );
971     }
972 
973     sal_Int32 nBottomMargin = m_nBottomMargin;
974     sal_Int32 nHeaderBottom = m_nHeaderBottom;
975     if ( HasFooter( bFirstPage ) )
976     {
977         nBottomMargin = nHeaderBottom;
978         if ( m_nBottomMargin > 0 && m_nBottomMargin > nHeaderBottom )
979             nHeaderBottom = m_nBottomMargin - nHeaderBottom;
980         else
981             nHeaderBottom = 0;
982         if ( nHeaderBottom < MIN_HEAD_FOOT_HEIGHT )
983             nHeaderBottom = MIN_HEAD_FOOT_HEIGHT;
984     }
985 
986     if ( m_nBottomMargin >= 0 ) //fixed height footer -> see WW8Par6.hxx
987     {
988         Insert( PROP_FOOTER_IS_DYNAMIC_HEIGHT, uno::makeAny( true ) );
989         Insert( PROP_FOOTER_DYNAMIC_SPACING, uno::makeAny( true ) );
990         Insert( PROP_FOOTER_BODY_DISTANCE, uno::makeAny( nHeaderBottom - MIN_HEAD_FOOT_HEIGHT ) );
991         Insert( PROP_FOOTER_HEIGHT, uno::makeAny( nHeaderBottom ) );
992 
993         if (bCopyFirstToFollow && HasFooter(/*bFirstPage=*/true))
994         {
995             m_aFollowPageStyle->setPropertyValue("FooterDynamicSpacing",
996                                                  getProperty(PROP_FOOTER_DYNAMIC_SPACING)->second);
997             m_aFollowPageStyle->setPropertyValue("FooterHeight",
998                                                  getProperty(PROP_FOOTER_HEIGHT)->second);
999         }
1000     }
1001     else
1002     {
1003         //todo: old filter fakes a frame into the header/footer to support overlapping
1004         //current setting is completely wrong!
1005         Insert( PROP_FOOTER_IS_DYNAMIC_HEIGHT, uno::makeAny( false ) );
1006         Insert( PROP_FOOTER_DYNAMIC_SPACING, uno::makeAny( false ) );
1007         Insert( PROP_FOOTER_HEIGHT, uno::makeAny( m_nBottomMargin - nHeaderBottom ) );
1008         Insert( PROP_FOOTER_BODY_DISTANCE, uno::makeAny( nHeaderBottom ) );
1009     }
1010 
1011     //now set the top/bottom margin for the follow page style
1012     Insert( PROP_TOP_MARGIN, uno::makeAny( std::max<sal_Int32>(nTopMargin, 0) ) );
1013     Insert( PROP_BOTTOM_MARGIN, uno::makeAny( std::max<sal_Int32>(nBottomMargin, 0) ) );
1014 
1015     if (bCopyFirstToFollow)
1016     {
1017         if (HasHeader(/*bFirstPage=*/true))
1018             m_aFollowPageStyle->setPropertyValue("TopMargin", getProperty(PROP_TOP_MARGIN)->second);
1019         if (HasFooter(/*bFirstPage=*/true))
1020             m_aFollowPageStyle->setPropertyValue("BottomMargin",
1021                                                  getProperty(PROP_BOTTOM_MARGIN)->second);
1022     }
1023 }
1024 
lcl_GetRangeProperties(bool bIsFirstSection,DomainMapper_Impl & rDM_Impl,const uno::Reference<text::XTextRange> & xStartingRange)1025 static uno::Reference< beans::XPropertySet > lcl_GetRangeProperties( bool bIsFirstSection,
1026                                                               DomainMapper_Impl& rDM_Impl,
1027                                                               const uno::Reference< text::XTextRange >& xStartingRange )
1028 {
1029     uno::Reference< beans::XPropertySet > xRangeProperties;
1030     if ( bIsFirstSection && rDM_Impl.GetBodyText().is() )
1031     {
1032         uno::Reference< container::XEnumerationAccess > xEnumAccess( rDM_Impl.GetBodyText(), uno::UNO_QUERY_THROW );
1033         uno::Reference< container::XEnumeration > xEnum = xEnumAccess->createEnumeration();
1034         xRangeProperties.set( xEnum->nextElement(), uno::UNO_QUERY_THROW );
1035         if ( rDM_Impl.GetIsDummyParaAddedForTableInSection() && xEnum->hasMoreElements() )
1036             xRangeProperties.set( xEnum->nextElement(), uno::UNO_QUERY_THROW );
1037     }
1038     else if ( xStartingRange.is() )
1039         xRangeProperties.set( xStartingRange, uno::UNO_QUERY_THROW );
1040     return xRangeProperties;
1041 }
1042 
HandleMarginsHeaderFooter(bool bFirstPage,DomainMapper_Impl & rDM_Impl)1043 void SectionPropertyMap::HandleMarginsHeaderFooter( bool bFirstPage, DomainMapper_Impl& rDM_Impl )
1044 {
1045     Insert( PROP_LEFT_MARGIN, uno::makeAny( m_nLeftMargin ) );
1046     Insert( PROP_RIGHT_MARGIN, uno::makeAny( m_nRightMargin ) );
1047 
1048     if ( rDM_Impl.m_oBackgroundColor )
1049         Insert( PROP_BACK_COLOR, uno::makeAny( *rDM_Impl.m_oBackgroundColor ) );
1050 
1051     // Check for missing footnote separator only in case there is at least
1052     // one footnote.
1053     if (rDM_Impl.m_bHasFtn && !rDM_Impl.m_bHasFtnSep)
1054     {
1055         // Set footnote line width to zero, document has no footnote separator.
1056         Insert(PROP_FOOTNOTE_LINE_RELATIVE_WIDTH, uno::makeAny(sal_Int32(0)));
1057     }
1058     if ( rDM_Impl.m_bHasFtnSep )
1059     {
1060         //If default paragraph style is RTL, footnote separator should be right aligned
1061         //and for RTL locales, LTR default paragraph style should present a left aligned footnote separator
1062         try
1063         {
1064             uno::Reference<style::XStyleFamiliesSupplier> xStylesSupplier(rDM_Impl.GetTextDocument(), uno::UNO_QUERY);
1065             if ( xStylesSupplier.is() )
1066             {
1067                 uno::Reference<container::XNameAccess> xStyleFamilies = xStylesSupplier->getStyleFamilies();
1068                 uno::Reference<container::XNameAccess> xParagraphStyles;
1069                 if ( xStyleFamilies.is() )
1070                     xStyleFamilies->getByName("ParagraphStyles") >>= xParagraphStyles;
1071                 uno::Reference<beans::XPropertySet> xStandard;
1072                 if ( xParagraphStyles.is() )
1073                     xParagraphStyles->getByName("Standard") >>= xStandard;
1074                 if ( xStandard.is() )
1075                 {
1076                     sal_Int16 aWritingMode(0);
1077                     xStandard->getPropertyValue( getPropertyName(PROP_WRITING_MODE) ) >>= aWritingMode;
1078                     if( aWritingMode == text::WritingMode2::RL_TB )
1079                         Insert( PROP_FOOTNOTE_LINE_ADJUST, uno::makeAny( sal_Int16(text::HorizontalAdjust_RIGHT) ), false );
1080                     else
1081                         Insert( PROP_FOOTNOTE_LINE_ADJUST, uno::makeAny( sal_Int16(text::HorizontalAdjust_LEFT) ), false );
1082                 }
1083             }
1084         }
1085         catch ( const uno::Exception& ) {}
1086     }
1087 
1088     /*** if headers/footers are available then the top/bottom margins of the
1089     header/footer are copied to the top/bottom margin of the page
1090     */
1091     CopyLastHeaderFooter( bFirstPage, rDM_Impl );
1092     PrepareHeaderFooterProperties( bFirstPage );
1093 }
1094 
FloatingTableConversion(const DomainMapper_Impl & rDM_Impl,FloatingTableInfo & rInfo)1095 bool SectionPropertyMap::FloatingTableConversion( const DomainMapper_Impl& rDM_Impl, FloatingTableInfo& rInfo )
1096 {
1097     // This is OOXML version of the code deciding if the table needs to be
1098     // in a floating frame.
1099     // For ww8 code, see SwWW8ImplReader::FloatingTableConversion in
1100     // sw/source/filter/ww8/ww8par.cxx
1101     // The two should do the same, so if you make changes here, please check
1102     // that the other is in sync.
1103 
1104     // Note that this is just a list of heuristics till sw core can have a
1105     // table that is floating and can span over multiple pages at the same
1106     // time.
1107 
1108     // If there is an explicit section break right after a table, then there
1109     // will be no wrapping anyway.
1110     if (rDM_Impl.m_bConvertedTable && !rDM_Impl.GetIsLastSectionGroup() && rInfo.m_nBreakType == NS_ooxml::LN_Value_ST_SectionMark_nextPage)
1111         return false;
1112 
1113     sal_Int32 nPageWidth = GetPageWidth();
1114     sal_Int32 nTextAreaWidth = nPageWidth - GetLeftMargin() - GetRightMargin();
1115     // Count the layout width of the table.
1116     sal_Int32 nTableWidth = rInfo.m_nTableWidth;
1117     if (rInfo.m_nTableWidthType == text::SizeType::VARIABLE)
1118     {
1119         nTableWidth *= nTextAreaWidth / 100.0;
1120     }
1121     sal_Int32 nLeftMargin = 0;
1122     if ( rInfo.getPropertyValue( "LeftMargin" ) >>= nLeftMargin )
1123         nTableWidth += nLeftMargin;
1124     sal_Int32 nRightMargin = 0;
1125     if ( rInfo.getPropertyValue( "RightMargin" ) >>= nRightMargin )
1126         nTableWidth += nRightMargin;
1127 
1128     sal_Int16 nHoriOrientRelation = rInfo.getPropertyValue( "HoriOrientRelation" ).get<sal_Int16>();
1129     sal_Int16 nVertOrientRelation = rInfo.getPropertyValue( "VertOrientRelation" ).get<sal_Int16>();
1130     if ( nHoriOrientRelation == text::RelOrientation::PAGE_FRAME && nVertOrientRelation == text::RelOrientation::PAGE_FRAME )
1131     {
1132         sal_Int16 nHoriOrient = rInfo.getPropertyValue( "HoriOrient" ).get<sal_Int16>();
1133         sal_Int16 nVertOrient = rInfo.getPropertyValue( "VertOrient" ).get<sal_Int16>();
1134         if ( nHoriOrient == text::HoriOrientation::NONE && nVertOrient == text::VertOrientation::NONE )
1135         {
1136             // Anchor position is relative to the page horizontally and vertically as well and is an absolute position.
1137             // The more close we are to the left edge, the less likely there will be any wrapping.
1138             // The more close we are to the bottom, the more likely the table will span over to the next page
1139             // So if we're in the bottom left quarter, don't do any conversion.
1140             sal_Int32 nHoriOrientPosition = rInfo.getPropertyValue( "HoriOrientPosition" ).get<sal_Int32>();
1141             sal_Int32 nVertOrientPosition = rInfo.getPropertyValue( "VertOrientPosition" ).get<sal_Int32>();
1142             sal_Int32 nPageHeight = getProperty( PROP_HEIGHT )->second.get<sal_Int32>();
1143             if ( nHoriOrientPosition < (nPageWidth / 2) && nVertOrientPosition >( nPageHeight / 2 ) )
1144                 return false;
1145         }
1146     }
1147 
1148     // It seems Word has a limit here, so that in case the table width is quite
1149     // close to the text area width, then it won't perform a wrapping, even in
1150     // case the content (e.g. an empty paragraph) would fit. The magic constant
1151     // here represents this limit.
1152     const sal_Int32 nMagicNumber = 469;
1153 
1154     // If the table's with is smaller than the text area width, text might
1155     // be next to the table and so it should behave as a floating table.
1156     if ( (nTableWidth + nMagicNumber) < nTextAreaWidth )
1157         return true;
1158 
1159     // If the position is relative to the edge of the page, then we need to check the whole
1160     // page width to see whether text can fit next to the table.
1161     if ( nHoriOrientRelation == text::RelOrientation::PAGE_FRAME )
1162     {
1163         // If the table is wide enough so that no text fits next to it, then don't create a fly
1164         // for the table: no wrapping will be performed anyway, but multi-page
1165         // tables will be broken.
1166         if ((nTableWidth + nMagicNumber) < (nPageWidth - std::min(GetLeftMargin(), GetRightMargin())))
1167             return true;
1168     }
1169 
1170     // If there are columns, always create the fly, otherwise the columns would
1171     // restrict geometry of the table.
1172     if ( ColumnCount() + 1 >= 2 )
1173         return true;
1174 
1175     return false;
1176 }
1177 
InheritOrFinalizePageStyles(DomainMapper_Impl & rDM_Impl)1178 void SectionPropertyMap::InheritOrFinalizePageStyles( DomainMapper_Impl& rDM_Impl )
1179 {
1180     // if no new styles have been created for this section, inherit from the previous section,
1181     // otherwise apply this section's settings to the new style.
1182     // Ensure that FollowPage is inherited first - otherwise GetPageStyle may auto-create a follow when checking FirstPage.
1183     SectionPropertyMap* pLastContext = rDM_Impl.GetLastSectionContext();
1184     //tdf124637 TODO: identify and skip special sections (like footnotes/endnotes)
1185     if ( pLastContext && m_sFollowPageStyleName.isEmpty() )
1186         m_sFollowPageStyleName = pLastContext->GetPageStyleName();
1187     else
1188     {
1189         HandleMarginsHeaderFooter( /*bFirst=*/false, rDM_Impl );
1190         GetPageStyle( rDM_Impl, /*bFirst=*/false );
1191         if ( rDM_Impl.IsNewDoc() && m_aFollowPageStyle.is() )
1192             ApplyProperties_( m_aFollowPageStyle );
1193     }
1194 
1195     // FirstPageStyle may only be inherited if it will not be used or re-linked to a different follow
1196     if ( !m_bTitlePage && pLastContext && m_sFirstPageStyleName.isEmpty() )
1197         m_sFirstPageStyleName = pLastContext->GetPageStyleName( /*bFirst=*/true );
1198     else
1199     {
1200         HandleMarginsHeaderFooter( /*bFirst=*/true, rDM_Impl );
1201         GetPageStyle( rDM_Impl, /*bFirst=*/true );
1202         if ( rDM_Impl.IsNewDoc() && m_aFirstPageStyle.is() )
1203             ApplyProperties_( m_aFirstPageStyle );
1204 
1205         // Chain m_aFollowPageStyle to be after m_aFirstPageStyle
1206         m_aFirstPageStyle->setPropertyValue( "FollowStyle", uno::makeAny( m_sFollowPageStyleName ) );
1207     }
1208 }
1209 
HandleIncreasedAnchoredObjectSpacing(DomainMapper_Impl & rDM_Impl)1210 void SectionPropertyMap::HandleIncreasedAnchoredObjectSpacing(DomainMapper_Impl& rDM_Impl)
1211 {
1212     // Ignore Word 2010 and older.
1213     if (rDM_Impl.GetSettingsTable()->GetWordCompatibilityMode() < 15)
1214         return;
1215 
1216     sal_Int32 nPageWidth = GetPageWidth();
1217     sal_Int32 nTextAreaWidth = nPageWidth - GetLeftMargin() - GetRightMargin();
1218 
1219     std::vector<AnchoredObjectsInfo>& rAnchoredObjectAnchors = rDM_Impl.m_aAnchoredObjectAnchors;
1220     for (const auto& rAnchor : rAnchoredObjectAnchors)
1221     {
1222         // Ignore this paragraph when there are not enough shapes to trigger the Word bug we
1223         // emulate.
1224         if (rAnchor.m_aAnchoredObjects.size() < 4)
1225             continue;
1226 
1227         // Ignore this paragraph if none of the objects are wrapped in the background.
1228         sal_Int32 nOpaqueCount = 0;
1229         for (const auto& rAnchored : rAnchor.m_aAnchoredObjects)
1230         {
1231             uno::Reference<beans::XPropertySet> xShape(rAnchored.m_xAnchoredObject, uno::UNO_QUERY);
1232             if (!xShape.is())
1233             {
1234                 continue;
1235             }
1236 
1237             bool bOpaque = true;
1238             xShape->getPropertyValue("Opaque") >>= bOpaque;
1239             if (!bOpaque)
1240             {
1241                 ++nOpaqueCount;
1242             }
1243         }
1244         if (nOpaqueCount < 1)
1245         {
1246             continue;
1247         }
1248 
1249         // Analyze the anchored objects of this paragraph, now that we know the
1250         // page width.
1251         sal_Int32 nShapesWidth = 0;
1252         for (const auto& rAnchored : rAnchor.m_aAnchoredObjects)
1253         {
1254             uno::Reference<drawing::XShape> xShape(rAnchored.m_xAnchoredObject, uno::UNO_QUERY);
1255             if (!xShape.is())
1256                 continue;
1257 
1258             uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
1259             if (!xPropertySet.is())
1260                 continue;
1261 
1262             // Ignore objects with no wrapping.
1263             text::WrapTextMode eWrap = text::WrapTextMode_THROUGH;
1264             xPropertySet->getPropertyValue("Surround") >>= eWrap;
1265             if (eWrap == text::WrapTextMode_THROUGH)
1266                 continue;
1267 
1268             // Use the original left margin, in case GraphicImport::lcl_sprm() reduced the doc model
1269             // one to 0.
1270             sal_Int32 nLeftMargin = rAnchored.m_nLeftMargin;
1271             sal_Int32 nRightMargin = 0;
1272             xPropertySet->getPropertyValue("RightMargin") >>= nRightMargin;
1273             nShapesWidth += xShape->getSize().Width + nLeftMargin + nRightMargin;
1274         }
1275 
1276         // Ignore cases when we have enough horizontal space for the shapes.
1277         if (nTextAreaWidth > nShapesWidth)
1278             continue;
1279 
1280         sal_Int32 nHeight = 0;
1281         for (const auto& rAnchored : rAnchor.m_aAnchoredObjects)
1282         {
1283             uno::Reference<drawing::XShape> xShape(rAnchored.m_xAnchoredObject, uno::UNO_QUERY);
1284             if (!xShape.is())
1285                 continue;
1286 
1287             nHeight += xShape->getSize().Height;
1288         }
1289 
1290         uno::Reference<beans::XPropertySet> xParagraph(rAnchor.m_xParagraph, uno::UNO_QUERY);
1291         if (xParagraph.is())
1292         {
1293             sal_Int32 nTopMargin = 0;
1294             xParagraph->getPropertyValue("ParaTopMargin") >>= nTopMargin;
1295             // Increase top spacing of the paragraph to match Word layout
1296             // behavior.
1297             nTopMargin = std::max(nTopMargin, nHeight);
1298             xParagraph->setPropertyValue("ParaTopMargin", uno::makeAny(nTopMargin));
1299         }
1300     }
1301     rAnchoredObjectAnchors.clear();
1302 }
1303 
CloseSectionGroup(DomainMapper_Impl & rDM_Impl)1304 void SectionPropertyMap::CloseSectionGroup( DomainMapper_Impl& rDM_Impl )
1305 {
1306     // The default section type is nextPage.
1307     if ( m_nBreakType == -1 )
1308         m_nBreakType = NS_ooxml::LN_Value_ST_SectionMark_nextPage;
1309     // if page orientation differs from previous section, it can't be treated as continuous
1310     else if ( m_nBreakType == NS_ooxml::LN_Value_ST_SectionMark_continuous )
1311     {
1312         SectionPropertyMap* pLastContext = rDM_Impl.GetLastSectionContext();
1313         if ( pLastContext )
1314         {
1315             bool bIsLandscape = false;
1316             boost::optional< PropertyMap::Property > pProp = getProperty( PROP_IS_LANDSCAPE );
1317             if ( pProp )
1318                 pProp->second >>= bIsLandscape;
1319 
1320             bool bPrevIsLandscape = false;
1321             pProp = pLastContext->getProperty( PROP_IS_LANDSCAPE );
1322             if ( pProp )
1323                 pProp->second >>= bPrevIsLandscape;
1324 
1325             if ( bIsLandscape != bPrevIsLandscape )
1326                 m_nBreakType = NS_ooxml::LN_Value_ST_SectionMark_nextPage;
1327         }
1328     }
1329 
1330     // Text area width is known at the end of a section: decide if tables should be converted or not.
1331     std::vector<FloatingTableInfo>& rPendingFloatingTables = rDM_Impl.m_aPendingFloatingTables;
1332     uno::Reference<text::XTextAppendAndConvert> xBodyText( rDM_Impl.GetBodyText(), uno::UNO_QUERY );
1333     for ( FloatingTableInfo & rInfo : rPendingFloatingTables )
1334     {
1335         rInfo.m_nBreakType = m_nBreakType;
1336         if ( FloatingTableConversion( rDM_Impl, rInfo ) )
1337         {
1338             try
1339             {
1340                 xBodyText->convertToTextFrame(rInfo.m_xStart, rInfo.m_xEnd,
1341                                               rInfo.m_aFrameProperties);
1342             }
1343             catch (const uno::Exception&)
1344             {
1345                 DBG_UNHANDLED_EXCEPTION("writerfilter", "convertToTextFrame() failed");
1346             }
1347         }
1348     }
1349     rPendingFloatingTables.clear();
1350 
1351     try
1352     {
1353         HandleIncreasedAnchoredObjectSpacing(rDM_Impl);
1354     }
1355     catch (const uno::Exception&)
1356     {
1357         DBG_UNHANDLED_EXCEPTION("writerfilter", "HandleIncreasedAnchoredObjectSpacing() failed");
1358     }
1359 
1360     if ( m_nLnnMod )
1361     {
1362         bool bFirst = rDM_Impl.IsLineNumberingSet();
1363         rDM_Impl.SetLineNumbering( m_nLnnMod, m_nLnc, m_ndxaLnn );
1364         if ( m_nLnnMin > 0 || (bFirst && m_nLnc == NS_ooxml::LN_Value_ST_LineNumberRestart_newSection) )
1365         {
1366             //set the starting value at the beginning of the section
1367             try
1368             {
1369                 uno::Reference< beans::XPropertySet > xRangeProperties;
1370                 if ( m_xStartingRange.is() )
1371                 {
1372                     xRangeProperties.set( m_xStartingRange, uno::UNO_QUERY_THROW );
1373                 }
1374                 else
1375                 {
1376                     //set the start value at the beginning of the document
1377                     xRangeProperties.set( rDM_Impl.GetTextDocument()->getText()->getStart(), uno::UNO_QUERY_THROW );
1378                 }
1379                 // Writer is 1-based, Word is 0-based.
1380                 xRangeProperties->setPropertyValue(
1381                     getPropertyName(PROP_PARA_LINE_NUMBER_START_VALUE),
1382                     uno::makeAny(m_nLnnMin + 1));
1383             }
1384             catch ( const uno::Exception& )
1385             {
1386                 DBG_UNHANDLED_EXCEPTION("writerfilter.dmapper", "Exception in SectionPropertyMap::CloseSectionGroup");
1387             }
1388         }
1389     }
1390 
1391     if (m_nBreakType == static_cast<sal_Int32>(NS_ooxml::LN_Value_ST_SectionMark_continuous)
1392         && !rDM_Impl.IsInComments())
1393     {
1394         //todo: insert a section or access the already inserted section
1395         uno::Reference< beans::XPropertySet > xSection =
1396             rDM_Impl.appendTextSectionAfter( m_xStartingRange );
1397         if ( xSection.is() )
1398         {
1399             if ( m_nColumnCount > 0 )
1400                 ApplyColumnProperties( xSection, rDM_Impl );
1401 
1402             ApplyProtectionProperties( xSection, rDM_Impl );
1403         }
1404 
1405         try
1406         {
1407             InheritOrFinalizePageStyles( rDM_Impl );
1408             ApplySectionProperties( xSection, rDM_Impl );  //depends on InheritOrFinalizePageStyles
1409             OUString aName = m_bTitlePage ? m_sFirstPageStyleName : m_sFollowPageStyleName;
1410             uno::Reference< beans::XPropertySet > xRangeProperties( lcl_GetRangeProperties( m_bIsFirstSection, rDM_Impl, m_xStartingRange ) );
1411             if ( m_bIsFirstSection && !aName.isEmpty() && xRangeProperties.is() )
1412             {
1413                 xRangeProperties->setPropertyValue( getPropertyName( PROP_PAGE_DESC_NAME ), uno::makeAny( aName ) );
1414             }
1415             else if ((!m_bFirstPageHeaderLinkToPrevious ||
1416                       !m_bFirstPageFooterLinkToPrevious ||
1417                       !m_bDefaultHeaderLinkToPrevious ||
1418                       !m_bDefaultFooterLinkToPrevious ||
1419                       !m_bEvenPageHeaderLinkToPrevious ||
1420                       !m_bEvenPageFooterLinkToPrevious)
1421                     && rDM_Impl.GetCurrentXText())
1422             {   // find a node in the section that has a page break and change
1423                 // it to apply the page style; see "nightmare scenario" in
1424                 // wwSectionManager::InsertSegments()
1425                 auto xTextAppend = rDM_Impl.GetCurrentXText();
1426                 uno::Reference<container::XEnumerationAccess> const xCursor(
1427                     xTextAppend->createTextCursorByRange(
1428                         uno::Reference<text::XTextContent>(xSection, uno::UNO_QUERY_THROW)->getAnchor()),
1429                     uno::UNO_QUERY_THROW);
1430                 uno::Reference<container::XEnumeration> const xEnum(
1431                         xCursor->createEnumeration());
1432                 bool isFound = false;
1433                 while (xEnum->hasMoreElements())
1434                 {
1435                     uno::Reference<beans::XPropertySet> xElem;
1436                     xEnum->nextElement() >>= xElem;
1437                     if (xElem->getPropertySetInfo()->hasPropertyByName("BreakType"))
1438                     {
1439                         style::BreakType bt;
1440                         if ((xElem->getPropertyValue("BreakType") >>= bt)
1441                             && bt == style::BreakType_PAGE_BEFORE)
1442                         {
1443                             // tdf#112201: do *not* use m_sFirstPageStyleName here!
1444                             xElem->setPropertyValue(getPropertyName(PROP_PAGE_DESC_NAME),
1445                                     uno::makeAny(m_sFollowPageStyleName));
1446                             isFound = true;
1447                             break;
1448                         }
1449                     }
1450                 }
1451                 if (!isFound)
1452                 {   // HACK: try the last paragraph of the previous section
1453                     uno::Reference<text::XParagraphCursor> const xPCursor(xCursor, uno::UNO_QUERY_THROW);
1454                     xPCursor->gotoPreviousParagraph(false);
1455                     uno::Reference<beans::XPropertySet> const xPSCursor(xCursor, uno::UNO_QUERY_THROW);
1456                     style::BreakType bt;
1457                     if ((xPSCursor->getPropertyValue("BreakType") >>= bt)
1458                         && bt == style::BreakType_PAGE_BEFORE)
1459                     {
1460                         xPSCursor->setPropertyValue(getPropertyName(PROP_PAGE_DESC_NAME),
1461                                 uno::makeAny(m_sFollowPageStyleName));
1462                     }
1463                 }
1464             }
1465         }
1466         catch ( const uno::Exception& )
1467         {
1468             SAL_WARN( "writerfilter", "failed to set PageDescName!" );
1469         }
1470     }
1471     // If the section is of type "New column" (0x01), then simply insert a column break.
1472     // But only if there actually are columns on the page, otherwise a column break
1473     // seems to be handled like a page break by MSO.
1474     else if (m_nBreakType == static_cast<sal_Int32>(NS_ooxml::LN_Value_ST_SectionMark_nextColumn)
1475             && 0 < m_nColumnCount && !rDM_Impl.IsInComments())
1476     {
1477         try
1478         {
1479             InheritOrFinalizePageStyles( rDM_Impl );
1480             uno::Reference< beans::XPropertySet > xRangeProperties;
1481             if ( m_xStartingRange.is() )
1482             {
1483                 xRangeProperties.set( m_xStartingRange, uno::UNO_QUERY_THROW );
1484             }
1485             else
1486             {
1487                 //set the start value at the beginning of the document
1488                 xRangeProperties.set( rDM_Impl.GetTextDocument()->getText()->getStart(), uno::UNO_QUERY_THROW );
1489             }
1490             xRangeProperties->setPropertyValue( getPropertyName( PROP_BREAK_TYPE ), uno::makeAny( style::BreakType_COLUMN_BEFORE ) );
1491         }
1492         catch ( const uno::Exception& ) {}
1493     }
1494     else if (!rDM_Impl.IsInComments())
1495     {
1496         uno::Reference< beans::XPropertySet > xSection;
1497         ApplyProtectionProperties( xSection, rDM_Impl );
1498 
1499         //get the properties and create appropriate page styles
1500         uno::Reference< beans::XPropertySet > xFollowPageStyle = GetPageStyle( rDM_Impl, false );
1501 
1502         HandleMarginsHeaderFooter(/*bFirstPage=*/false, rDM_Impl );
1503 
1504         if ( rDM_Impl.GetSettingsTable()->GetMirrorMarginSettings() )
1505         {
1506             Insert( PROP_PAGE_STYLE_LAYOUT, uno::makeAny( style::PageStyleLayout_MIRRORED ) );
1507         }
1508         uno::Reference< text::XTextColumns > xColumns;
1509         if ( m_nColumnCount > 0 )
1510         {
1511             // prefer setting column properties into a section, not a page style if at all possible.
1512             if ( !xSection.is() )
1513                 xSection = rDM_Impl.appendTextSectionAfter( m_xStartingRange );
1514             if ( xSection.is() )
1515                 ApplyColumnProperties( xSection, rDM_Impl );
1516             else
1517                 xColumns = ApplyColumnProperties( xFollowPageStyle, rDM_Impl );
1518         }
1519 
1520         // these BreakTypes are effectively page-breaks: don't evenly distribute text in columns before a page break;
1521         SectionPropertyMap* pLastContext = rDM_Impl.GetLastSectionContext();
1522         if ( pLastContext && pLastContext->ColumnCount() )
1523             pLastContext->DontBalanceTextColumns();
1524 
1525         //prepare text grid properties
1526         sal_Int32 nHeight = 1;
1527         boost::optional< PropertyMap::Property > pProp = getProperty( PROP_HEIGHT );
1528         if ( pProp )
1529             pProp->second >>= nHeight;
1530 
1531         sal_Int32 nWidth = 1;
1532         pProp = getProperty( PROP_WIDTH );
1533         if ( pProp )
1534             pProp->second >>= nWidth;
1535 
1536         text::WritingMode eWritingMode = text::WritingMode_LR_TB;
1537         pProp = getProperty( PROP_WRITING_MODE );
1538         if ( pProp )
1539             pProp->second >>= eWritingMode;
1540 
1541         sal_Int32 nTextAreaHeight = eWritingMode == text::WritingMode_LR_TB ?
1542             nHeight - m_nTopMargin - m_nBottomMargin :
1543             nWidth - m_nLeftMargin - m_nRightMargin;
1544 
1545         sal_Int32 nGridLinePitch = m_nGridLinePitch;
1546         //sep.dyaLinePitch
1547         if ( nGridLinePitch < 1 || nGridLinePitch > 31680 )
1548         {
1549             SAL_WARN( "writerfilter", "sep.dyaLinePitch outside legal range: " << nGridLinePitch );
1550             nGridLinePitch = 1;
1551         }
1552 
1553         const sal_Int32 nGridLines = nTextAreaHeight / nGridLinePitch;
1554         if ( nGridLines >= 0 && nGridLines <= SAL_MAX_INT16 )
1555             Insert( PROP_GRID_LINES, uno::makeAny( sal_Int16(nGridLines) ) );
1556 
1557         // PROP_GRID_MODE
1558         Insert( PROP_GRID_MODE, uno::makeAny( static_cast<sal_Int16> (m_nGridType) ) );
1559         if ( m_nGridType == text::TextGridMode::LINES_AND_CHARS )
1560         {
1561             Insert( PROP_GRID_SNAP_TO_CHARS, uno::makeAny( m_bGridSnapToChars ) );
1562         }
1563 
1564         sal_Int32 nCharWidth = 423; //240 twip/ 12 pt
1565         const StyleSheetEntryPtr pEntry = rDM_Impl.GetStyleSheetTable()->FindStyleSheetByConvertedStyleName( "Standard" );
1566         if ( pEntry.get() )
1567         {
1568             boost::optional< PropertyMap::Property > pPropHeight = pEntry->pProperties->getProperty( PROP_CHAR_HEIGHT_ASIAN );
1569             if ( pPropHeight )
1570             {
1571                 double fHeight = 0;
1572                 if ( pPropHeight->second >>= fHeight )
1573                     nCharWidth = ConversionHelper::convertTwipToMM100( static_cast<long>(fHeight * 20.0 + 0.5) );
1574             }
1575         }
1576 
1577         //dxtCharSpace
1578         if ( m_nDxtCharSpace )
1579         {
1580             sal_Int32 nCharSpace = m_nDxtCharSpace;
1581             //main lives in top 20 bits, and is signed.
1582             sal_Int32 nMain = (nCharSpace & 0xFFFFF000);
1583             nMain /= 0x1000;
1584             nCharWidth += ConversionHelper::convertTwipToMM100( nMain * 20 );
1585 
1586             sal_Int32 nFraction = (nCharSpace & 0x00000FFF);
1587             nFraction = (nFraction * 20) / 0xFFF;
1588             nCharWidth += ConversionHelper::convertTwipToMM100( nFraction );
1589         }
1590 
1591         if ( m_nPageNumberType >= 0 )
1592             Insert( PROP_NUMBERING_TYPE, uno::makeAny( m_nPageNumberType ) );
1593 
1594         // #i119558#, force to set document as standard page mode,
1595         // refer to ww8 import process function "SwWW8ImplReader::SetDocumentGrid"
1596         try
1597         {
1598             uno::Reference< beans::XPropertySet > xDocProperties;
1599             xDocProperties.set( rDM_Impl.GetTextDocument(), uno::UNO_QUERY_THROW );
1600             Insert(PROP_GRID_STANDARD_MODE, uno::makeAny(true));
1601             xDocProperties->setPropertyValue("DefaultPageMode", uno::makeAny(false));
1602         }
1603         catch ( const uno::Exception& )
1604         {
1605             DBG_UNHANDLED_EXCEPTION("writerfilter.dmapper", "Exception in SectionPropertyMap::CloseSectionGroup");
1606         }
1607 
1608         Insert( PROP_GRID_BASE_HEIGHT, uno::makeAny( nGridLinePitch ) );
1609         Insert( PROP_GRID_BASE_WIDTH, uno::makeAny( nCharWidth ) );
1610         Insert( PROP_GRID_RUBY_HEIGHT, uno::makeAny( sal_Int32( 0 ) ) );
1611 
1612         if ( rDM_Impl.IsNewDoc() )
1613             ApplyProperties_( xFollowPageStyle );
1614 
1615         //todo: creating a "First Page" style depends on HasTitlePage and _fFacingPage_
1616         if ( m_bTitlePage )
1617         {
1618             CopyLastHeaderFooter( true, rDM_Impl );
1619             PrepareHeaderFooterProperties( true );
1620             uno::Reference< beans::XPropertySet > xFirstPageStyle = GetPageStyle(
1621                 rDM_Impl, true );
1622             if ( rDM_Impl.IsNewDoc() )
1623                 ApplyProperties_( xFirstPageStyle );
1624 
1625             if ( xColumns.is() )
1626                 xFirstPageStyle->setPropertyValue(
1627                     getPropertyName( PROP_TEXT_COLUMNS ), uno::makeAny( xColumns ) );
1628         }
1629 
1630         ApplyBorderToPageStyles( rDM_Impl, m_eBorderApply, m_eBorderOffsetFrom );
1631 
1632         try
1633         {
1634             //now apply this break at the first paragraph of this section
1635             uno::Reference< beans::XPropertySet > xRangeProperties( lcl_GetRangeProperties( m_bIsFirstSection, rDM_Impl, m_xStartingRange ) );
1636 
1637             // Handle page breaks with odd/even page numbering. We need to use an extra page style for setting the page style
1638             // to left/right, because if we set it to the normal style, we'd set it to "First Page"/"Default Style", which would
1639             // break them (all default pages would be only left or right).
1640             if ( m_nBreakType == static_cast<sal_Int32>(NS_ooxml::LN_Value_ST_SectionMark_evenPage) || m_nBreakType == static_cast<sal_Int32>(NS_ooxml::LN_Value_ST_SectionMark_oddPage) )
1641             {
1642                 OUString* pageStyle = m_bTitlePage ? &m_sFirstPageStyleName : &m_sFollowPageStyleName;
1643                 OUString evenOddStyleName = rDM_Impl.GetUnusedPageStyleName();
1644                 uno::Reference< beans::XPropertySet > evenOddStyle(
1645                     rDM_Impl.GetTextFactory()->createInstance( "com.sun.star.style.PageStyle" ),
1646                     uno::UNO_QUERY );
1647                 // Unfortunately using setParent() does not work for page styles, so make a deep copy of the page style.
1648                 uno::Reference< beans::XPropertySet > pageProperties( m_bTitlePage ? m_aFirstPageStyle : m_aFollowPageStyle );
1649                 uno::Reference< beans::XPropertySetInfo > pagePropertiesInfo( pageProperties->getPropertySetInfo() );
1650                 const uno::Sequence< beans::Property > propertyList( pagePropertiesInfo->getProperties() );
1651                 // Ignore write-only properties.
1652                 static const o3tl::sorted_vector<OUString> aBlacklist
1653                     = { "FooterBackGraphicURL", "BackGraphicURL", "HeaderBackGraphicURL" };
1654                 for ( const auto& rProperty : propertyList )
1655                 {
1656                     if ( (rProperty.Attributes & beans::PropertyAttribute::READONLY) == 0 )
1657                     {
1658                         if (aBlacklist.find(rProperty.Name) == aBlacklist.end())
1659                             evenOddStyle->setPropertyValue(
1660                                 rProperty.Name,
1661                                 pageProperties->getPropertyValue(rProperty.Name));
1662                     }
1663                 }
1664                 evenOddStyle->setPropertyValue( "FollowStyle", uno::makeAny( *pageStyle ) );
1665                 rDM_Impl.GetPageStyles()->insertByName( evenOddStyleName, uno::makeAny( evenOddStyle ) );
1666                 evenOddStyle->setPropertyValue( "HeaderIsOn", uno::makeAny( false ) );
1667                 evenOddStyle->setPropertyValue( "FooterIsOn", uno::makeAny( false ) );
1668                 CopyHeaderFooter( pageProperties, evenOddStyle );
1669                 *pageStyle = evenOddStyleName; // And use it instead of the original one (which is set as follow of this one).
1670                 if ( m_nBreakType == static_cast<sal_Int32>(NS_ooxml::LN_Value_ST_SectionMark_evenPage) )
1671                     evenOddStyle->setPropertyValue( getPropertyName( PROP_PAGE_STYLE_LAYOUT ), uno::makeAny( style::PageStyleLayout_LEFT ) );
1672                 else if ( m_nBreakType == static_cast<sal_Int32>(NS_ooxml::LN_Value_ST_SectionMark_oddPage) )
1673                     evenOddStyle->setPropertyValue( getPropertyName( PROP_PAGE_STYLE_LAYOUT ), uno::makeAny( style::PageStyleLayout_RIGHT ) );
1674             }
1675 
1676             if ( xRangeProperties.is() && rDM_Impl.IsNewDoc() )
1677             {
1678                 // Avoid setting page style in case of autotext: so inserting the autotext at the
1679                 // end of the document does not introduce an unwanted page break.
1680                 if (!rDM_Impl.IsReadGlossaries() && !rDM_Impl.IsInFootOrEndnote())
1681                 {
1682                     xRangeProperties->setPropertyValue(
1683                         getPropertyName( PROP_PAGE_DESC_NAME ),
1684                         uno::makeAny( m_bTitlePage ? m_sFirstPageStyleName
1685                             : m_sFollowPageStyleName ) );
1686                 }
1687 
1688                 if (0 <= m_nPageNumber)
1689                 {
1690                     sal_Int16 nPageNumber = static_cast< sal_Int16 >(m_nPageNumber);
1691                     xRangeProperties->setPropertyValue(getPropertyName(PROP_PAGE_NUMBER_OFFSET),
1692                         uno::makeAny(nPageNumber));
1693                 }
1694             }
1695         }
1696         catch ( const uno::Exception& )
1697         {
1698             OSL_FAIL( "Exception in SectionPropertyMap::CloseSectionGroup" );
1699         }
1700     }
1701 
1702     // Now that the margins are known, resize relative width shapes because some shapes in LO do not support percentage-sizes
1703     sal_Int32 nParagraphWidth = GetPageWidth() - m_nLeftMargin - m_nRightMargin;
1704     if ( m_nColumnCount > 0 )
1705     {
1706         // skip custom-width columns since we don't know what column the shape is in.
1707         if ( !m_aColWidth.empty() )
1708             nParagraphWidth = 0;
1709         else
1710             nParagraphWidth = (nParagraphWidth - (m_nColumnDistance * m_nColumnCount)) / (m_nColumnCount + 1);
1711     }
1712     if ( nParagraphWidth > 0 )
1713     {
1714         const OUString sPropRelativeWidth = getPropertyName(PROP_RELATIVE_WIDTH);
1715         for ( const auto& xShape : m_xRelativeWidthShapes )
1716         {
1717             const uno::Reference<beans::XPropertySet> xShapePropertySet( xShape, uno::UNO_QUERY );
1718             if ( xShapePropertySet->getPropertySetInfo()->hasPropertyByName(sPropRelativeWidth) )
1719             {
1720                 sal_uInt16 nPercent = 0;
1721                 try
1722                 {
1723                     xShapePropertySet->getPropertyValue(sPropRelativeWidth) >>= nPercent;
1724                 }
1725                 catch (const css::uno::RuntimeException& e)
1726                 {
1727                     // May happen e.g. when text frame has no frame format
1728                     // See sw/qa/extras/ooxmlimport/data/n779627.docx
1729                     SAL_WARN("writerfilter", "Getting relative width failed. " << e.Message);
1730                 }
1731                 if ( nPercent )
1732                 {
1733                     const sal_Int32 nWidth = nParagraphWidth * nPercent / 100;
1734                     xShape->setSize( awt::Size( nWidth, xShape->getSize().Height ) );
1735                 }
1736             }
1737         }
1738     }
1739     m_xRelativeWidthShapes.clear();
1740 
1741     rDM_Impl.SetIsLastSectionGroup( false );
1742     rDM_Impl.SetIsFirstParagraphInSection( true );
1743 
1744     if ( !rDM_Impl.IsInFootOrEndnote() )
1745     {
1746         rDM_Impl.m_bHasFtn = false;
1747         rDM_Impl.m_bHasFtnSep = false;
1748     }
1749 }
1750 
1751 // Clear the flag that says we should take the header/footer content from
1752 // the previous section.  This should be called when we encounter a header
1753 // or footer definition for this section.
ClearHeaderFooterLinkToPrevious(bool bHeader,PageType eType)1754 void SectionPropertyMap::ClearHeaderFooterLinkToPrevious( bool bHeader, PageType eType )
1755 {
1756     if ( bHeader )
1757     {
1758         switch ( eType )
1759         {
1760             case PAGE_FIRST: m_bFirstPageHeaderLinkToPrevious = false; break;
1761             case PAGE_LEFT:  m_bEvenPageHeaderLinkToPrevious = false; break;
1762             case PAGE_RIGHT: m_bDefaultHeaderLinkToPrevious = false; break;
1763                 // no default case as all enumeration values have been covered
1764         }
1765     }
1766     else
1767     {
1768         switch ( eType )
1769         {
1770             case PAGE_FIRST: m_bFirstPageFooterLinkToPrevious = false; break;
1771             case PAGE_LEFT:  m_bEvenPageFooterLinkToPrevious = false; break;
1772             case PAGE_RIGHT: m_bDefaultFooterLinkToPrevious = false; break;
1773         }
1774     }
1775 }
1776 
1777 class NamedPropertyValue
1778 {
1779 private:
1780     OUString const m_aName;
1781 
1782 public:
NamedPropertyValue(const OUString & i_aStr)1783     explicit NamedPropertyValue( const OUString& i_aStr )
1784         : m_aName( i_aStr )
1785     {
1786     }
1787 
operator ()(beans::PropertyValue const & aVal)1788     bool operator() ( beans::PropertyValue const & aVal )
1789     {
1790         return aVal.Name == m_aName;
1791     }
1792 };
1793 
ApplyProperties_(const uno::Reference<beans::XPropertySet> & xStyle)1794 void SectionPropertyMap::ApplyProperties_( const uno::Reference< beans::XPropertySet >& xStyle )
1795 {
1796     uno::Reference< beans::XMultiPropertySet > const xMultiSet( xStyle, uno::UNO_QUERY );
1797 
1798     std::vector< OUString > vNames;
1799     std::vector< uno::Any > vValues;
1800     {
1801         // Convert GetPropertyValues() value into something useful
1802         uno::Sequence< beans::PropertyValue > vPropVals = GetPropertyValues();
1803 
1804         //Temporarily store the items that are in grab bags
1805         uno::Sequence< beans::PropertyValue > vCharVals;
1806         uno::Sequence< beans::PropertyValue > vParaVals;
1807         beans::PropertyValue* pCharGrabBag = std::find_if( vPropVals.begin(), vPropVals.end(), NamedPropertyValue( "CharInteropGrabBag" ) );
1808         if ( pCharGrabBag != vPropVals.end() )
1809             (pCharGrabBag->Value) >>= vCharVals;
1810         beans::PropertyValue* pParaGrabBag = std::find_if( vPropVals.begin(), vPropVals.end(), NamedPropertyValue( "ParaInteropGrabBag" ) );
1811         if ( pParaGrabBag != vPropVals.end() )
1812             (pParaGrabBag->Value) >>= vParaVals;
1813 
1814         for ( beans::PropertyValue* pIter = vPropVals.begin(); pIter != vPropVals.end(); ++pIter )
1815         {
1816             if ( pIter != pCharGrabBag && pIter != pParaGrabBag
1817                  && pIter->Name != "IsProtected" //section-only property
1818                )
1819             {
1820                 vNames.push_back( pIter->Name );
1821                 vValues.push_back( pIter->Value );
1822             }
1823         }
1824         for ( const beans::PropertyValue & v : std::as_const(vCharVals) )
1825         {
1826             vNames.push_back( v.Name );
1827             vValues.push_back( v.Value );
1828         }
1829         for ( const beans::PropertyValue & v : std::as_const(vParaVals) )
1830         {
1831             vNames.push_back( v.Name );
1832             vValues.push_back( v.Value );
1833         }
1834     }
1835     if ( xMultiSet.is() )
1836     {
1837         try
1838         {
1839             xMultiSet->setPropertyValues( comphelper::containerToSequence( vNames ), comphelper::containerToSequence( vValues ) );
1840             return;
1841         }
1842         catch ( const uno::Exception& )
1843         {
1844             OSL_FAIL( "Exception in SectionPropertyMap::ApplyProperties_" );
1845         }
1846     }
1847     for ( size_t i = 0; i < vNames.size(); ++i )
1848     {
1849         try
1850         {
1851             if ( xStyle.is() )
1852                 xStyle->setPropertyValue( vNames[i], vValues[i] );
1853         }
1854         catch ( const uno::Exception& )
1855         {
1856             OSL_FAIL( "Exception in SectionPropertyMap::ApplyProperties_" );
1857         }
1858     }
1859 }
1860 
GetPageWidth() const1861 sal_Int32 SectionPropertyMap::GetPageWidth() const
1862 {
1863     return getProperty( PROP_WIDTH )->second.get<sal_Int32>();
1864 }
1865 
StyleSheetPropertyMap()1866 StyleSheetPropertyMap::StyleSheetPropertyMap()
1867     : mnListLevel( -1 )
1868     , mnOutlineLevel( -1 )
1869     , mnNumId( -1 )
1870 {
1871 }
1872 
ParagraphProperties()1873 ParagraphProperties::ParagraphProperties()
1874     : m_bFrameMode( false )
1875     , m_nDropCap( NS_ooxml::LN_Value_doc_ST_DropCap_none )
1876     , m_nLines( 0 )
1877     , m_w( -1 )
1878     , m_h( -1 )
1879     , m_nWrap( text::WrapTextMode::WrapTextMode_MAKE_FIXED_SIZE )
1880     , m_hAnchor( -1 )
1881     , m_vAnchor( -1 )
1882     , m_x( -1 )
1883     , m_bxValid( false )
1884     , m_y( -1 )
1885     , m_byValid( false )
1886     , m_hSpace( -1 )
1887     , m_vSpace( -1 )
1888     , m_hRule( -1 )
1889     , m_xAlign( -1 )
1890     , m_yAlign( -1 )
1891     , m_nDropCapLength( 0 )
1892 {
1893 }
1894 
operator ==(const ParagraphProperties & rCompare)1895 bool ParagraphProperties::operator==( const ParagraphProperties& rCompare )
1896 {
1897     return ( m_bFrameMode  == rCompare.m_bFrameMode &&
1898              m_nDropCap    == rCompare.m_nDropCap &&
1899              m_nLines      == rCompare.m_nLines &&
1900              m_w           == rCompare.m_w &&
1901              m_h           == rCompare.m_h &&
1902              m_nWrap       == rCompare.m_nWrap &&
1903              m_hAnchor     == rCompare.m_hAnchor &&
1904              m_vAnchor     == rCompare.m_vAnchor &&
1905              m_x           == rCompare.m_x &&
1906              m_bxValid     == rCompare.m_bxValid &&
1907              m_y           == rCompare.m_y &&
1908              m_byValid     == rCompare.m_byValid &&
1909              m_hSpace      == rCompare.m_hSpace &&
1910              m_vSpace      == rCompare.m_vSpace &&
1911              m_hRule       == rCompare.m_hRule &&
1912              m_xAlign      == rCompare.m_xAlign &&
1913              m_yAlign      == rCompare.m_yAlign );
1914 }
1915 
ResetFrameProperties()1916 void ParagraphProperties::ResetFrameProperties()
1917 {
1918     m_bFrameMode     = false;
1919     m_nDropCap       = NS_ooxml::LN_Value_doc_ST_DropCap_none;
1920     m_nLines         = 0;
1921     m_w              = -1;
1922     m_h              = -1;
1923     m_nWrap          = text::WrapTextMode::WrapTextMode_MAKE_FIXED_SIZE;
1924     m_hAnchor        = -1;
1925     m_vAnchor        = -1;
1926     m_x              = -1;
1927     m_bxValid        = false;
1928     m_y              = -1;
1929     m_byValid        = false;
1930     m_hSpace         = -1;
1931     m_vSpace         = -1;
1932     m_hRule          = -1;
1933     m_xAlign         = -1;
1934     m_yAlign         = -1;
1935     m_nDropCapLength = 0;
1936 }
1937 
getValue(TablePropertyMapTarget eWhich,sal_Int32 & nFill)1938 bool TablePropertyMap::getValue( TablePropertyMapTarget eWhich, sal_Int32& nFill )
1939 {
1940     if ( eWhich < TablePropertyMapTarget_MAX )
1941     {
1942         if ( m_aValidValues[eWhich].bValid )
1943             nFill = m_aValidValues[eWhich].nValue;
1944         return m_aValidValues[eWhich].bValid;
1945     }
1946     else
1947     {
1948         OSL_FAIL( "invalid TablePropertyMapTarget" );
1949         return false;
1950     }
1951 }
1952 
setValue(TablePropertyMapTarget eWhich,sal_Int32 nSet)1953 void TablePropertyMap::setValue( TablePropertyMapTarget eWhich, sal_Int32 nSet )
1954 {
1955     if ( eWhich < TablePropertyMapTarget_MAX )
1956     {
1957         m_aValidValues[eWhich].bValid = true;
1958         m_aValidValues[eWhich].nValue = nSet;
1959     }
1960     else
1961         OSL_FAIL( "invalid TablePropertyMapTarget" );
1962 }
1963 
insertTableProperties(const PropertyMap * pMap,const bool bOverwrite)1964 void TablePropertyMap::insertTableProperties( const PropertyMap* pMap, const bool bOverwrite )
1965 {
1966 #ifdef DBG_UTIL
1967     TagLogger::getInstance().startElement( "TablePropertyMap.insertTableProperties" );
1968     pMap->dumpXml();
1969 #endif
1970 
1971     const TablePropertyMap* pSource = dynamic_cast< const TablePropertyMap* >(pMap);
1972     if ( pSource )
1973     {
1974         for ( sal_Int32 eTarget = TablePropertyMapTarget_START;
1975             eTarget < TablePropertyMapTarget_MAX; ++eTarget )
1976         {
1977             if ( pSource->m_aValidValues[eTarget].bValid && (bOverwrite || !m_aValidValues[eTarget].bValid) )
1978             {
1979                 m_aValidValues[eTarget].bValid = true;
1980                 m_aValidValues[eTarget].nValue = pSource->m_aValidValues[eTarget].nValue;
1981             }
1982         }
1983     }
1984 
1985 #ifdef DBG_UTIL
1986     dumpXml();
1987     TagLogger::getInstance().endElement();
1988 #endif
1989 }
1990 
1991 } // namespace dmapper
1992 } // namespace writerfilter
1993 
1994 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1995