summaryrefslogtreecommitdiff
path: root/writerfilter
diff options
context:
space:
mode:
authorMike Kaganski <mike.kaganski@collabora.com>2018-03-14 10:18:15 +0300
committerJan Holesovsky <kendy@collabora.com>2018-07-20 12:13:14 +0200
commit0f3ba021f7a9072306beec3d279179f4bae35afc (patch)
treec9c6126f2e11b5979ff21a3fefe943c492e7622d /writerfilter
parent4807f573336dddfecd9b44b515aefa39ab26aa23 (diff)
tdf#112118: DOCX: properly import/export border distance
https://wiki.openoffice.org/wiki/Writer/MSInteroperability/PageBorder discusses implementation differences between ODF model and MS formats wrt dealing with page margins and distances to borders. This patch corrects import from DOCX, so that the border distance and width doesn't add to the margin size imported from file anymore. It takes care to preserve size from page edge to text (the most important size that affects document layout). When borders go outside of range valid for ODF, the margin is set to keep text area intact, and the border is placed as close to intended position as possible. Export code now also properly handles border width. Also, an improved heuristic implemented to better export cases unsupported by Word, so that the result would look closer to ODF original. We still write correct sizes to OOXML, so that when reopened by LO, the borders will be in correct places; but as Word cannot handle sizes more than 31 pt, it will show borders shifted. This prevents from adding border widths and distances to page margins at each opening of DOCX, saving back the changed value, increasing the margins each time. This also backports commit 6d20aeeda8a346ac10782d44214a89878fd00c40 Change-Id: Ia978ab119dd661949d6c321aea91397f28d205b0 Reviewed-on: https://gerrit.libreoffice.org/51267 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/57703 Tested-by: Mike Kaganski <mike.kaganski@collabora.com> Reviewed-by: Jan Holesovsky <kendy@collabora.com>
Diffstat (limited to 'writerfilter')
-rw-r--r--writerfilter/source/dmapper/DomainMapper.cxx1
-rw-r--r--writerfilter/source/dmapper/PageBordersHandler.cxx16
-rw-r--r--writerfilter/source/dmapper/PageBordersHandler.hxx8
-rw-r--r--writerfilter/source/dmapper/PropertyMap.cxx73
-rw-r--r--writerfilter/source/dmapper/PropertyMap.hxx23
5 files changed, 77 insertions, 44 deletions
diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx
index abfc8694535c..8aabcd02bce2 100644
--- a/writerfilter/source/dmapper/DomainMapper.cxx
+++ b/writerfilter/source/dmapper/DomainMapper.cxx
@@ -2154,7 +2154,6 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const PropertyMapPtr& rContext )
// Set the borders to the context and apply them to the styles
pHandler->SetBorders( pSectionContext );
- pSectionContext->SetBorderParams( pHandler->GetDisplayOffset( ) );
}
}
break;
diff --git a/writerfilter/source/dmapper/PageBordersHandler.cxx b/writerfilter/source/dmapper/PageBordersHandler.cxx
index f9fe9685692b..2bebf0d5af6b 100644
--- a/writerfilter/source/dmapper/PageBordersHandler.cxx
+++ b/writerfilter/source/dmapper/PageBordersHandler.cxx
@@ -37,8 +37,8 @@ PgBorder::~PgBorder( )
PageBordersHandler::PageBordersHandler( ) :
LoggedProperties("PageBordersHandler"),
-m_nDisplay( 0 ),
-m_nOffset( 0 )
+m_eBorderApply(SectionPropertyMap::BorderApply::ToAllInSection),
+m_eOffsetFrom(SectionPropertyMap::BorderOffsetFrom::Text)
{
}
@@ -57,13 +57,13 @@ void PageBordersHandler::lcl_attribute( Id eName, Value& rVal )
{
default:
case NS_ooxml::LN_Value_doc_ST_PageBorderDisplay_allPages:
- m_nDisplay = 0;
+ m_eBorderApply = SectionPropertyMap::BorderApply::ToAllInSection;
break;
case NS_ooxml::LN_Value_doc_ST_PageBorderDisplay_firstPage:
- m_nDisplay = 1;
+ m_eBorderApply = SectionPropertyMap::BorderApply::ToFirstPageInSection;
break;
case NS_ooxml::LN_Value_doc_ST_PageBorderDisplay_notFirstPage:
- m_nDisplay = 2;
+ m_eBorderApply = SectionPropertyMap::BorderApply::ToAllButFirstInSection;
break;
}
}
@@ -74,10 +74,10 @@ void PageBordersHandler::lcl_attribute( Id eName, Value& rVal )
{
default:
case NS_ooxml::LN_Value_doc_ST_PageBorderOffset_page:
- m_nOffset = 1;
+ m_eOffsetFrom = SectionPropertyMap::BorderOffsetFrom::Edge;
break;
case NS_ooxml::LN_Value_doc_ST_PageBorderOffset_text:
- m_nOffset = 0;
+ m_eOffsetFrom = SectionPropertyMap::BorderOffsetFrom::Text;
break;
}
}
@@ -137,6 +137,8 @@ void PageBordersHandler::SetBorders( SectionPropertyMap* pSectContext )
{
pSectContext->SetBorder( rBorder.m_ePos, rBorder.m_nDistance, rBorder.m_rLine, rBorder.m_bShadow );
}
+ pSectContext->SetBorderApply(m_eBorderApply);
+ pSectContext->SetBorderOffsetFrom(m_eOffsetFrom);
}
} }
diff --git a/writerfilter/source/dmapper/PageBordersHandler.hxx b/writerfilter/source/dmapper/PageBordersHandler.hxx
index 6ced273953af..7ce2e15eba79 100644
--- a/writerfilter/source/dmapper/PageBordersHandler.hxx
+++ b/writerfilter/source/dmapper/PageBordersHandler.hxx
@@ -50,8 +50,8 @@ class PageBordersHandler : public LoggedProperties
private:
// See implementation of SectionPropertyMap::ApplyBorderToPageStyles
- sal_Int32 m_nDisplay;
- sal_Int32 m_nOffset;
+ SectionPropertyMap::BorderApply m_eBorderApply;
+ SectionPropertyMap::BorderOffsetFrom m_eOffsetFrom;
std::vector<PgBorder> m_aBorders;
// Properties
@@ -62,10 +62,6 @@ public:
PageBordersHandler( );
virtual ~PageBordersHandler( ) override;
- sal_Int32 GetDisplayOffset( )
- {
- return ( m_nOffset << 5 ) + m_nDisplay;
- };
void SetBorders( SectionPropertyMap* pSectContext );
};
diff --git a/writerfilter/source/dmapper/PropertyMap.cxx b/writerfilter/source/dmapper/PropertyMap.cxx
index af4133a7625e..88e6deea5090 100644
--- a/writerfilter/source/dmapper/PropertyMap.cxx
+++ b/writerfilter/source/dmapper/PropertyMap.cxx
@@ -364,7 +364,8 @@ void PropertyMap::printProperties()
SectionPropertyMap::SectionPropertyMap( bool bIsFirstSection )
: m_bIsFirstSection( bIsFirstSection )
- , m_nBorderParams( 0 )
+ , m_eBorderApply( BorderApply::ToAllInSection )
+ , m_eBorderOffsetFrom( BorderOffsetFrom::Text )
, m_bTitlePage( false )
, m_nColumnCount( 0 )
, m_nColumnDistance( 1249 )
@@ -526,7 +527,7 @@ void SectionPropertyMap::SetBorder( BorderPosition ePos, sal_Int32 nLineDistance
void SectionPropertyMap::ApplyBorderToPageStyles( const uno::Reference< container::XNameContainer >& xPageStyles,
const uno::Reference < lang::XMultiServiceFactory >& xTextFactory,
- sal_Int32 nValue )
+ BorderApply eBorderApply, BorderOffsetFrom eOffsetFrom )
{
/*
page border applies to:
@@ -543,25 +544,24 @@ void SectionPropertyMap::ApplyBorderToPageStyles( const uno::Reference< containe
*/
uno::Reference< beans::XPropertySet > xFirst;
uno::Reference< beans::XPropertySet > xSecond;
- sal_Int32 nOffsetFrom = (nValue & 0x00E0) >> 5;
// todo: negative spacing (from ww8par6.cxx)
- switch ( nValue & 0x07 )
+ switch ( eBorderApply )
{
- case 0: // all styles
+ case BorderApply::ToAllInSection: // all styles
if ( !m_sFollowPageStyleName.isEmpty() )
xFirst = GetPageStyle( xPageStyles, xTextFactory, false );
if ( !m_sFirstPageStyleName.isEmpty() )
xSecond = GetPageStyle( xPageStyles, xTextFactory, true );
break;
- case 1: // first page
+ case BorderApply::ToFirstPageInSection: // first page
if ( !m_sFirstPageStyleName.isEmpty() )
xFirst = GetPageStyle( xPageStyles, xTextFactory, true );
break;
- case 2: // left and right
+ case BorderApply::ToAllButFirstInSection: // left and right
if ( !m_sFollowPageStyleName.isEmpty() )
xFirst = GetPageStyle( xPageStyles, xTextFactory, false );
break;
- case 3: // whole document?
+ case BorderApply::ToWholeDocument: // whole document?
// todo: how to apply a border to the whole document - find all sections or access all page styles?
default:
return;
@@ -609,10 +609,10 @@ void SectionPropertyMap::ApplyBorderToPageStyles( const uno::Reference< containe
nLineWidth = m_oBorderLines[nBorder]->LineWidth;
if ( xFirst.is() )
SetBorderDistance( xFirst, aMarginIds[nBorder], aBorderDistanceIds[nBorder],
- m_nBorderDistances[nBorder], nOffsetFrom, nLineWidth );
+ m_nBorderDistances[nBorder], eOffsetFrom, nLineWidth );
if ( xSecond.is() )
SetBorderDistance( xSecond, aMarginIds[nBorder], aBorderDistanceIds[nBorder],
- m_nBorderDistances[nBorder], nOffsetFrom, nLineWidth );
+ m_nBorderDistances[nBorder], eOffsetFrom, nLineWidth );
}
}
@@ -643,26 +643,47 @@ void SectionPropertyMap::SetBorderDistance( const uno::Reference< beans::XProper
PropertyIds eMarginId,
PropertyIds eDistId,
sal_Int32 nDistance,
- sal_Int32 nOffsetFrom,
+ BorderOffsetFrom eOffsetFrom,
sal_uInt32 nLineWidth )
{
- sal_Int32 nDist = nDistance;
- if ( nOffsetFrom == 1 ) // From page
- {
- const OUString sMarginName = getPropertyName( eMarginId );
- uno::Any aMargin = xStyle->getPropertyValue( sMarginName );
- sal_Int32 nMargin = 0;
- aMargin >>= nMargin;
+ // See https://wiki.openoffice.org/wiki/Writer/MSInteroperability/PageBorder
- // Change the margins with the border distance
- xStyle->setPropertyValue( sMarginName, uno::makeAny( nDistance ) );
+ if (!xStyle.is())
+ return;
+ const OUString sMarginName = getPropertyName( eMarginId );
+ const OUString sBorderDistanceName = getPropertyName( eDistId );
+ uno::Any aMargin = xStyle->getPropertyValue( sMarginName );
+ sal_Int32 nMargin = 0;
+ aMargin >>= nMargin;
+ sal_Int32 nNewMargin = nMargin;
+ sal_Int32 nNewDist = nDistance;
- // Set the distance to ( Margin - distance - nLineWidth )
- nDist = nMargin - nDistance - nLineWidth;
+ switch (eOffsetFrom)
+ {
+ case BorderOffsetFrom::Text:
+ nNewMargin -= nDistance + nLineWidth;
+ break;
+ case BorderOffsetFrom::Edge:
+ nNewMargin = nDistance;
+ nNewDist = nMargin - nDistance - nLineWidth;
+ break;
}
- const OUString sBorderDistanceName = getPropertyName( eDistId );
- if ( xStyle.is() )
- xStyle->setPropertyValue( sBorderDistanceName, uno::makeAny( nDist ) );
+ // Ensure corrent distance from page edge to text in cases not supported by us:
+ // when border is outside entire page area (eOffsetFrom == Text && nDistance > nMargin),
+ // and when border is inside page body area (eOffsetFrom == Edge && nDistance > nMargin)
+ if (nNewMargin < 0)
+ {
+ nNewMargin = 0;
+ nNewDist = std::max<sal_Int32>(nMargin - nLineWidth, 0);
+ }
+ else if (nNewDist < 0)
+ {
+ nNewMargin = std::max<sal_Int32>(nMargin - nLineWidth, 0);
+ nNewDist = 0;
+ }
+ // Change the margins with the border distance
+ xStyle->setPropertyValue( sMarginName, uno::makeAny( nNewMargin ) );
+ xStyle->setPropertyValue( sBorderDistanceName, uno::makeAny( nNewDist ) );
}
void SectionPropertyMap::DontBalanceTextColumns()
@@ -1441,7 +1462,7 @@ void SectionPropertyMap::CloseSectionGroup( DomainMapper_Impl& rDM_Impl )
getPropertyName( PROP_TEXT_COLUMNS ), uno::makeAny( xColumns ) );
}
- ApplyBorderToPageStyles( rDM_Impl.GetPageStyles(), rDM_Impl.GetTextFactory(), m_nBorderParams );
+ ApplyBorderToPageStyles( rDM_Impl.GetPageStyles(), rDM_Impl.GetTextFactory(), m_eBorderApply, m_eBorderOffsetFrom );
try
{
diff --git a/writerfilter/source/dmapper/PropertyMap.hxx b/writerfilter/source/dmapper/PropertyMap.hxx
index 2412c8e0126e..ad82bcf617fc 100644
--- a/writerfilter/source/dmapper/PropertyMap.hxx
+++ b/writerfilter/source/dmapper/PropertyMap.hxx
@@ -181,6 +181,19 @@ typedef std::shared_ptr< PropertyMap > PropertyMapPtr;
class SectionPropertyMap : public PropertyMap
{
+public:
+ enum class BorderApply
+ {
+ ToAllInSection = 0,
+ ToFirstPageInSection = 1,
+ ToAllButFirstInSection = 2,
+ ToWholeDocument = 3,
+ };
+ enum class BorderOffsetFrom
+ {
+ Text = 0,
+ Edge = 1,
+ };
private:
#ifdef DEBUG_WRITERFILTER
sal_Int32 m_nDebugSectionNumber;
@@ -199,7 +212,8 @@ private:
boost::optional< css::table::BorderLine2 > m_oBorderLines[4];
sal_Int32 m_nBorderDistances[4];
- sal_Int32 m_nBorderParams;
+ BorderApply m_eBorderApply;
+ BorderOffsetFrom m_eBorderOffsetFrom;
bool m_bBorderShadows[4];
bool m_bTitlePage;
@@ -273,7 +287,7 @@ private:
PropertyIds eMarginId,
PropertyIds eDistId,
sal_Int32 nDistance,
- sal_Int32 nOffsetFrom,
+ BorderOffsetFrom eOffsetFrom,
sal_uInt32 nLineWidth );
// Determines if conversion of a given floating table is wanted or not.
@@ -313,7 +327,8 @@ public:
void InheritOrFinalizePageStyles( DomainMapper_Impl& rDM_Impl );
void SetBorder( BorderPosition ePos, sal_Int32 nLineDistance, const css::table::BorderLine2& rBorderLine, bool bShadow );
- void SetBorderParams( sal_Int32 nSet ) { m_nBorderParams = nSet; }
+ void SetBorderApply( BorderApply nSet ) { m_eBorderApply = nSet; }
+ void SetBorderOffsetFrom( BorderOffsetFrom nSet ) { m_eBorderOffsetFrom = nSet; }
void SetColumnCount( sal_Int16 nCount ) { m_nColumnCount = nCount; }
sal_Int16 ColumnCount() const { return m_nColumnCount; }
@@ -354,7 +369,7 @@ public:
// determine which style gets the borders
void ApplyBorderToPageStyles( const css::uno::Reference< css::container::XNameContainer >& xStyles,
const css::uno::Reference< css::lang::XMultiServiceFactory >& xTextFactory,
- sal_Int32 nValue );
+ BorderApply eBorderApply, BorderOffsetFrom eOffsetFrom );
void CloseSectionGroup( DomainMapper_Impl& rDM_Impl );
// Handling of margins, header and footer for any kind of sections breaks.