summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sw/qa/extras/ooxmlexport/data/tdf112118.docxbin0 -> 11698 bytes
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport11.cxx32
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.cxx165
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.hxx18
-rw-r--r--writerfilter/source/dmapper/PageBordersHandler.cxx17
-rw-r--r--writerfilter/source/dmapper/PageBordersHandler.hxx8
-rw-r--r--writerfilter/source/dmapper/PropertyMap.cxx75
-rw-r--r--writerfilter/source/dmapper/PropertyMap.hxx23
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
new file mode 100644
index 000000000000..87081d8c6dd9
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/tdf112118.docx
Binary files differ
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.