diff options
-rw-r--r-- | sw/qa/extras/ooxmlexport/data/tdf112118.docx | bin | 0 -> 11698 bytes | |||
-rw-r--r-- | sw/qa/extras/ooxmlexport/ooxmlexport11.cxx | 32 | ||||
-rw-r--r-- | sw/source/filter/ww8/docxattributeoutput.cxx | 165 | ||||
-rw-r--r-- | sw/source/filter/ww8/docxattributeoutput.hxx | 18 | ||||
-rw-r--r-- | writerfilter/source/dmapper/PageBordersHandler.cxx | 17 | ||||
-rw-r--r-- | writerfilter/source/dmapper/PageBordersHandler.hxx | 8 | ||||
-rw-r--r-- | writerfilter/source/dmapper/PropertyMap.cxx | 75 | ||||
-rw-r--r-- | writerfilter/source/dmapper/PropertyMap.hxx | 23 |
8 files changed, 227 insertions, 111 deletions
diff --git a/sw/qa/extras/ooxmlexport/data/tdf112118.docx b/sw/qa/extras/ooxmlexport/data/tdf112118.docx Binary files differnew file mode 100644 index 000000000000..87081d8c6dd9 --- /dev/null +++ b/sw/qa/extras/ooxmlexport/data/tdf112118.docx diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx index 4fdc51170d49..239786d5f8eb 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx @@ -11,6 +11,7 @@ #include <com/sun/star/awt/Size.hpp> #include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/table/BorderLine.hpp> #include <com/sun/star/text/XDependentTextField.hpp> #include <com/sun/star/text/XFootnote.hpp> #include <com/sun/star/text/XPageCursor.hpp> @@ -280,6 +281,37 @@ DECLARE_OOXMLEXPORT_TEST(testTdf107035, "tdf107035.docx") CPPUNIT_ASSERT_EQUAL(sal_Int32(COL_AUTO), nPgNumColour); } +DECLARE_OOXMLEXPORT_TEST(testTdf112118, "tdf112118.docx") +{ + auto xStyles = getStyles("PageStyles"); + auto testProc = [&](const OUString& sStyleName, sal_Int32 nMargin, sal_Int32 nBorderDistance, + sal_Int16 nBorderWidth) + { + typedef std::initializer_list<OUStringLiteral> StringList; + uno::Reference<beans::XPropertySet> xStyle(xStyles->getByName(sStyleName), uno::UNO_QUERY_THROW); + for (const auto& side : StringList{ "Top", "Left", "Bottom", "Right" }) + { + table::BorderLine aBorder = getProperty<table::BorderLine>(xStyle, side + "Border"); + CPPUNIT_ASSERT_EQUAL(sal_Int16(nBorderWidth), aBorder.OuterLineWidth); + CPPUNIT_ASSERT_EQUAL(sal_Int16(0), aBorder.InnerLineWidth); + CPPUNIT_ASSERT_EQUAL(sal_Int16(0), aBorder.LineDistance); + + sal_Int32 nMarginActual = getProperty<sal_Int32>(xStyle, side + "Margin"); + CPPUNIT_ASSERT_EQUAL(nMargin, nMarginActual); + + sal_Int32 nBorderDistanceActual = getProperty<sal_Int32>(xStyle, side + "BorderDistance"); + CPPUNIT_ASSERT_EQUAL(nBorderDistance, nBorderDistanceActual); + } + }; + + // For both styles used in document, the total distance from page edge to text must be 2.54 cm. + // The first style uses "from edge" border distance; the second uses "from text" border distance + // Border distances in both cases are 24 pt = 847 mm100; line widths are 6 pt = 212 mm100. + // 1482 + 847 + 212 = 2541 + testProc("Standard", 847, 1482, 212); + testProc("Converted1", 1482, 847, 212); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index 1cde1640af0b..21b4d57d4321 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -3036,8 +3036,6 @@ static OutputBorderOptions lcl_getTableDefaultBorderOptions(bool bEcma) rOptions.bWriteTag = true; rOptions.bWriteInsideHV = true; rOptions.bWriteDistance = false; - rOptions.aShadowLocation = SvxShadowLocation::NONE; - rOptions.bCheckDistanceSize = false; return rOptions; } @@ -3051,8 +3049,6 @@ static OutputBorderOptions lcl_getTableCellBorderOptions(bool bEcma) rOptions.bWriteTag = true; rOptions.bWriteInsideHV = true; rOptions.bWriteDistance = false; - rOptions.aShadowLocation = SvxShadowLocation::NONE; - rOptions.bCheckDistanceSize = false; return rOptions; } @@ -3066,23 +3062,103 @@ static OutputBorderOptions lcl_getBoxBorderOptions() rOptions.bWriteTag = false; rOptions.bWriteInsideHV = false; rOptions.bWriteDistance = true; - rOptions.aShadowLocation = SvxShadowLocation::NONE; - rOptions.bCheckDistanceSize = false; return rOptions; } -static bool boxHasLineLargerThan31(const SvxBoxItem& rBox) +struct BorderDistances { - return ( - ( rBox.GetDistance( SvxBoxItemLine::TOP ) / 20 ) > 31 || - ( rBox.GetDistance( SvxBoxItemLine::LEFT ) / 20 ) > 31 || - ( rBox.GetDistance( SvxBoxItemLine::BOTTOM ) / 20 ) > 31 || - ( rBox.GetDistance( SvxBoxItemLine::RIGHT ) / 20 ) > 31 - ); + bool bFromEdge = false; + sal_uInt16 nTop = 0; + sal_uInt16 nLeft = 0; + sal_uInt16 nBottom = 0; + sal_uInt16 nRight = 0; +}; + +// Heuristics to decide if we need to use "from edge" offset of borders +// +// There are two cases when we can safely use "from text" or "from edge" offset without distorting +// border position (modulo rounding errors): +// 1. When distance of all borders from text is no greater than 31 pt, we use "from text" +// 2. Otherwise, if distance of all borders from edge is no greater than 31 pt, we use "from edge" +// In all other cases, the position of borders would be distirted on export, because Word doesn't +// support the offset of >31 pts (https://msdn.microsoft.com/en-us/library/ff533820), and we need +// to decide which type of offset would provide less wrong result (i.e., the result would look +// closer to original). Here, we just check sum of distances from text to borders, and if it is +// less than sum of distances from borders to edges. The alternative would be to compare total areas +// between text-and-borders and between borders-and-edges (taking into account different lengths of +// borders, and visual impact of that). +static void CalculateExportDistances(const SvxBoxItem& rBox, const PageMargins& rMargins, + OutputBorderOptions& rOptions) +{ + rOptions.pDistances = std::make_shared<BorderDistances>(); + + const sal_uInt16 nT = rBox.GetDistance(SvxBoxItemLine::TOP); + const sal_uInt16 nL = rBox.GetDistance(SvxBoxItemLine::LEFT); + const sal_uInt16 nB = rBox.GetDistance(SvxBoxItemLine::BOTTOM); + const sal_uInt16 nR = rBox.GetDistance(SvxBoxItemLine::RIGHT); + + // Only take into account existing borders + const SvxBorderLine* pLnT = rBox.GetLine(SvxBoxItemLine::TOP); + const SvxBorderLine* pLnL = rBox.GetLine(SvxBoxItemLine::LEFT); + const SvxBorderLine* pLnB = rBox.GetLine(SvxBoxItemLine::BOTTOM); + const SvxBorderLine* pLnR = rBox.GetLine(SvxBoxItemLine::RIGHT); + + // We need to take border widths into account + const sal_uInt16 nWidthT = pLnT ? pLnT->GetWidth() : 0; + const sal_uInt16 nWidthL = pLnL ? pLnL->GetWidth() : 0; + const sal_uInt16 nWidthB = pLnB ? pLnB->GetWidth() : 0; + const sal_uInt16 nWidthR = pLnR ? pLnR->GetWidth() : 0; + + // Resulting distances from text to borders + const sal_uInt16 nT2BT = pLnT ? nT : 0; + const sal_uInt16 nT2BL = pLnL ? nL : 0; + const sal_uInt16 nT2BB = pLnB ? nB : 0; + const sal_uInt16 nT2BR = pLnR ? nR : 0; + + // Resulting distances from edge to borders + const sal_uInt16 nE2BT = pLnT ? rMargins.nPageMarginTop - nT - nWidthT : 0; + const sal_uInt16 nE2BL = pLnL ? rMargins.nPageMarginLeft - nL - nWidthL : 0; + const sal_uInt16 nE2BB = pLnB ? rMargins.nPageMarginBottom - nB - nWidthB : 0; + const sal_uInt16 nE2BR = pLnR ? rMargins.nPageMarginRight - nR - nWidthR : 0; + + // 1. If all borders are in range of 31 pts from text + if ((nT2BT / 20) <= 31 && (nT2BL / 20) <= 31 && (nT2BB / 20) <= 31 && (nT2BR / 20) <= 31) + { + rOptions.pDistances->bFromEdge = false; + } + else + { + // 2. If all borders are in range of 31 pts from edge + if ((nE2BT / 20) <= 31 && (nE2BL / 20) <= 31 && (nE2BB / 20) <= 31 && (nE2BR / 20) <= 31) + { + rOptions.pDistances->bFromEdge = true; + } + else + { + // Let's try to guess which would be the best approximation + rOptions.pDistances->bFromEdge = + (nT2BT + nT2BL + nT2BB + nT2BR) > (nE2BT + nE2BL + nE2BB + nE2BR); + } + } + + if (rOptions.pDistances->bFromEdge) + { + rOptions.pDistances->nTop = nE2BT; + rOptions.pDistances->nLeft = nE2BL; + rOptions.pDistances->nBottom = nE2BB; + rOptions.pDistances->nRight = nE2BR; + } + else + { + rOptions.pDistances->nTop = nT2BT; + rOptions.pDistances->nLeft = nT2BL; + rOptions.pDistances->nBottom = nT2BB; + rOptions.pDistances->nRight = nT2BR; + } } -static void impl_borders( FSHelperPtr const & pSerializer, const SvxBoxItem& rBox, const OutputBorderOptions& rOptions, PageMargins const * pageMargins, +static void impl_borders( FSHelperPtr const & pSerializer, const SvxBoxItem& rBox, const OutputBorderOptions& rOptions, std::map<SvxBoxItemLine, css::table::BorderLine2> &rTableStyleConf ) { static const SvxBoxItemLine aBorders[] = @@ -3100,16 +3176,6 @@ static void impl_borders( FSHelperPtr const & pSerializer, const SvxBoxItem& rBo bool tagWritten = false; const SvxBoxItemLine* pBrd = aBorders; - bool bExportDistanceFromPageEdge = false; - if ( rOptions.bCheckDistanceSize && boxHasLineLargerThan31(rBox) ) - { - // The distance is larger than '31'. This cannot be exported as 'distance from text'. - // Instead - it should be exported as 'distance from page edge'. - // This is based on http://wiki.openoffice.org/wiki/Writer/MSInteroperability/PageBorder - // Specifically 'export case #2' - bExportDistanceFromPageEdge = true; - } - bool bWriteInsideH = false; bool bWriteInsideV = false; for( int i = 0; i < 4; ++i, ++pBrd ) @@ -3158,22 +3224,20 @@ static void impl_borders( FSHelperPtr const & pSerializer, const SvxBoxItem& rBo sal_uInt16 nDist = 0; if (rOptions.bWriteDistance) { - if (bExportDistanceFromPageEdge) + if (rOptions.pDistances) { - // Export 'Distance from Page Edge' if ( *pBrd == SvxBoxItemLine::TOP) - nDist = pageMargins->nPageMarginTop - rBox.GetDistance( *pBrd ); + nDist = rOptions.pDistances->nTop; else if ( *pBrd == SvxBoxItemLine::LEFT) - nDist = pageMargins->nPageMarginLeft - rBox.GetDistance( *pBrd ); + nDist = rOptions.pDistances->nLeft; else if ( *pBrd == SvxBoxItemLine::BOTTOM) - nDist = pageMargins->nPageMarginBottom - rBox.GetDistance( *pBrd ); + nDist = rOptions.pDistances->nBottom; else if ( *pBrd == SvxBoxItemLine::RIGHT) - nDist = pageMargins->nPageMarginRight - rBox.GetDistance( *pBrd ); + nDist = rOptions.pDistances->nRight; } else { - // Export 'Distance from text' - nDist = rBox.GetDistance( *pBrd ); + nDist = rBox.GetDistance(*pBrd); } } @@ -3322,7 +3386,7 @@ void DocxAttributeOutput::TableCellProperties( ww8::WW8TableNodeInfoInner::Point const SvxBoxItem& rDefaultBox = (*tableFirstCells.rbegin())->getTableBox( )->GetFrameFormat( )->GetBox( ); { // The cell borders - impl_borders( m_pSerializer, rBox, lcl_getTableCellBorderOptions(bEcma), nullptr, m_aTableStyleConf ); + impl_borders( m_pSerializer, rBox, lcl_getTableCellBorderOptions(bEcma), m_aTableStyleConf ); } TableBackgrounds( pTableTextNodeInfoInner ); @@ -3826,7 +3890,7 @@ void DocxAttributeOutput::TableDefaultBorders( ww8::WW8TableNodeInfoInner::Point if (m_aTableStyleConf.empty()) { // the defaults of the table are taken from the top-left cell - impl_borders(m_pSerializer, pFrameFormat->GetBox(), lcl_getTableDefaultBorderOptions(bEcma), nullptr, m_aTableStyleConf); + impl_borders(m_pSerializer, pFrameFormat->GetBox(), lcl_getTableDefaultBorderOptions(bEcma), m_aTableStyleConf); } } @@ -6068,27 +6132,8 @@ void DocxAttributeOutput::SectionPageBorders( const SwFrameFormat* pFormat, cons if ( !(pBottom || pTop || pLeft || pRight) ) return; - bool bExportDistanceFromPageEdge = false; - if ( boxHasLineLargerThan31(rBox) ) - { - // The distance is larger than '31'. This cannot be exported as 'distance from text'. - // Instead - it should be exported as 'distance from page edge'. - // This is based on http://wiki.openoffice.org/wiki/Writer/MSInteroperability/PageBorder - // Specifically 'export case #2' - bExportDistanceFromPageEdge = true; - } - - // All distances are relative to the text margins - m_pSerializer->startElementNS( XML_w, XML_pgBorders, - FSNS( XML_w, XML_display ), "allPages", - FSNS( XML_w, XML_offsetFrom ), bExportDistanceFromPageEdge ? "page" : "text", - FSEND ); - OutputBorderOptions aOutputBorderOptions = lcl_getBoxBorderOptions(); - // Check if the distance is larger than 31 points - aOutputBorderOptions.bCheckDistanceSize = true; - // Check if there is a shadow item const SfxPoolItem* pItem = GetExport().HasItem( RES_SHADOW ); if ( pItem ) @@ -6106,9 +6151,16 @@ void DocxAttributeOutput::SectionPageBorders( const SwFrameFormat* pFormat, cons if (aGlue.HasFooter()) aMargins.nPageMarginBottom = aGlue.dyaHdrBottom; + CalculateExportDistances(rBox, aMargins, aOutputBorderOptions); + + // All distances are relative to the text margins + m_pSerializer->startElementNS(XML_w, XML_pgBorders, + FSNS(XML_w, XML_display), "allPages", + FSNS(XML_w, XML_offsetFrom), aOutputBorderOptions.pDistances->bFromEdge ? "page" : "text", + FSEND); + std::map<SvxBoxItemLine, css::table::BorderLine2> aEmptyMap; // empty styles map - impl_borders( m_pSerializer, rBox, aOutputBorderOptions, &aMargins, - aEmptyMap ); + impl_borders( m_pSerializer, rBox, aOutputBorderOptions, aEmptyMap ); m_pSerializer->endElementNS( XML_w, XML_pgBorders ); @@ -8570,8 +8622,7 @@ void DocxAttributeOutput::FormatBox( const SvxBoxItem& rBox ) m_pSerializer->startElementNS( XML_w, XML_pBdr, FSEND ); std::map<SvxBoxItemLine, css::table::BorderLine2> aEmptyMap; // empty styles map - impl_borders( m_pSerializer, rBox, aOutputBorderOptions, &m_pageMargins, - aEmptyMap ); + impl_borders( m_pSerializer, rBox, aOutputBorderOptions, aEmptyMap ); // Close the paragraph's borders tag m_pSerializer->endElementNS( XML_w, XML_pBdr ); diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx index edc9688d858f..887976a53931 100644 --- a/sw/source/filter/ww8/docxattributeoutput.hxx +++ b/sw/source/filter/ww8/docxattributeoutput.hxx @@ -68,6 +68,8 @@ enum DocxColBreakStatus COLBRK_WRITE }; +struct BorderDistances; + /** * A structure that holds information about the options selected * when outputting a border to DOCX. @@ -80,15 +82,13 @@ enum DocxColBreakStatus */ struct OutputBorderOptions { - sal_Int32 tag; - bool bUseStartEnd; - bool bWriteTag; - bool bWriteInsideHV; - bool bWriteDistance; - SvxShadowLocation aShadowLocation; - bool bCheckDistanceSize; - - OutputBorderOptions() : tag(0), bUseStartEnd(false), bWriteTag(true), bWriteInsideHV(false), bWriteDistance(false), aShadowLocation(SvxShadowLocation::NONE), bCheckDistanceSize(false) {} + sal_Int32 tag = 0; + bool bUseStartEnd = false; + bool bWriteTag = true; + bool bWriteInsideHV = false; + bool bWriteDistance = false; + SvxShadowLocation aShadowLocation = SvxShadowLocation::NONE; + std::shared_ptr<BorderDistances> pDistances; }; /** diff --git a/writerfilter/source/dmapper/PageBordersHandler.cxx b/writerfilter/source/dmapper/PageBordersHandler.cxx index fc1867be3c80..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,7 +137,8 @@ void PageBordersHandler::SetBorders( SectionPropertyMap* pSectContext ) { pSectContext->SetBorder( rBorder.m_ePos, rBorder.m_nDistance, rBorder.m_rLine, rBorder.m_bShadow ); } - pSectContext->SetBorderParams(GetDisplayOffset()); + 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 d20adca936fa..b58b6e20fb5f 100644 --- a/writerfilter/source/dmapper/PropertyMap.cxx +++ b/writerfilter/source/dmapper/PropertyMap.cxx @@ -365,7 +365,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 ) @@ -527,7 +528,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: @@ -544,25 +545,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; @@ -610,10 +610,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 ); } } @@ -644,26 +644,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; - - // Change the margins with the border distance - xStyle->setPropertyValue( sMarginName, uno::makeAny( nDistance ) ); + // See https://wiki.openoffice.org/wiki/Writer/MSInteroperability/PageBorder - // Set the distance to ( Margin - distance - nLineWidth ) - nDist = nMargin - nDistance - nLineWidth; - } + if (!xStyle.is()) + return; + const OUString sMarginName = getPropertyName( eMarginId ); const OUString sBorderDistanceName = getPropertyName( eDistId ); - if ( xStyle.is() ) - xStyle->setPropertyValue( sBorderDistanceName, uno::makeAny( nDist ) ); + uno::Any aMargin = xStyle->getPropertyValue( sMarginName ); + sal_Int32 nMargin = 0; + aMargin >>= nMargin; + sal_Int32 nNewMargin = nMargin; + sal_Int32 nNewDist = nDistance; + + switch (eOffsetFrom) + { + case BorderOffsetFrom::Text: + nNewMargin -= nDistance + nLineWidth; + break; + case BorderOffsetFrom::Edge: + nNewMargin = nDistance; + nNewDist = nMargin - nDistance - nLineWidth; + break; + } + // 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() @@ -1438,7 +1459,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 c373522d2792..07e1707a8a5a 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; @@ -275,7 +289,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. @@ -315,7 +329,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; } @@ -358,7 +373,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. |