summaryrefslogtreecommitdiff
path: root/sw/source/filter
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/filter')
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.cxx165
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.hxx18
2 files changed, 117 insertions, 66 deletions
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;
};
/**