diff options
author | Mike Kaganski <mike.kaganski@collabora.com> | 2018-03-15 20:48:53 +0300 |
---|---|---|
committer | Mike Kaganski <mike.kaganski@collabora.com> | 2018-03-16 04:54:47 +0100 |
commit | 8805e10f5887df66edfd0a2fa4b70e87f0c74700 (patch) | |
tree | 6754af5d8450787a2aab415a864377f704a84af1 /editeng | |
parent | 2537d6897ae516d3b4d50f0e2885dc24949841bf (diff) |
tdf#112118: DOC: properly import/export border distance
DOCX part was done in fb959e581c900b392efd0bb329b7cf30c8ed56a5.
This commit fixes DOC part. Line width wasn't taken into account on
import; and export was done only with "from text" distance, which
gave poor interoperability with Word, where the borders were close
to page edge.
The common code is moved to editeng/source/items/frmitems.cxx and
include/editeng/boxitem.hxx.
Change-Id: I3d1d1312cb9dc9a9e00d9847ec11234cd787df60
Reviewed-on: https://gerrit.libreoffice.org/51366
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Diffstat (limited to 'editeng')
-rw-r--r-- | editeng/source/items/frmitems.cxx | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/editeng/source/items/frmitems.cxx b/editeng/source/items/frmitems.cxx index 85790110bc78..ea1d15126ff3 100644 --- a/editeng/source/items/frmitems.cxx +++ b/editeng/source/items/frmitems.cxx @@ -2592,6 +2592,131 @@ bool SvxBoxInfoItem::PutValue( const uno::Any& rVal, sal_uInt8 nMemberId ) return true; } + +namespace editeng +{ + +void BorderDistanceFromWord(bool bFromEdge, sal_Int32& nMargin, sal_Int32& nBorderDistance, + sal_Int32 nBorderWidth) +{ + // See https://wiki.openoffice.org/wiki/Writer/MSInteroperability/PageBorder + + sal_Int32 nNewMargin = nMargin; + sal_Int32 nNewBorderDistance = nBorderDistance; + + if (bFromEdge) + { + nNewMargin = nBorderDistance; + nNewBorderDistance = nMargin - nBorderDistance - nBorderWidth; + } + else + { + nNewMargin -= nBorderDistance + nBorderWidth; + } + + // Ensure correct distance from page edge to text in cases not supported by us: + // when border is outside entire page area (!bFromEdge && BorderDistance > Margin), + // and when border is inside page body area (bFromEdge && BorderDistance > Margin) + if (nNewMargin < 0) + { + nNewMargin = 0; + nNewBorderDistance = std::max<sal_Int32>(nMargin - nBorderWidth, 0); + } + else if (nNewBorderDistance < 0) + { + nNewMargin = std::max<sal_Int32>(nMargin - nBorderWidth, 0); + nNewBorderDistance = 0; + } + + nMargin = nNewMargin; + nBorderDistance = nNewBorderDistance; +} + +// 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). +void BorderDistancesToWord(const SvxBoxItem& rBox, const WordPageMargins& rMargins, + WordBorderDistances& rDistances) +{ + // Use signed sal_Int32 that can hold sal_uInt16, to prevent overflow at substraction below + const sal_Int32 nT = rBox.GetDistance(SvxBoxItemLine::TOP); + const sal_Int32 nL = rBox.GetDistance(SvxBoxItemLine::LEFT); + const sal_Int32 nB = rBox.GetDistance(SvxBoxItemLine::BOTTOM); + const sal_Int32 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 long nWidthT = pLnT ? pLnT->GetWidth() : 0; + const long nWidthL = pLnL ? pLnL->GetWidth() : 0; + const long nWidthB = pLnB ? pLnB->GetWidth() : 0; + const long nWidthR = pLnR ? pLnR->GetWidth() : 0; + + // Resulting distances from text to borders + const sal_Int32 nT2BT = pLnT ? nT : 0; + const sal_Int32 nT2BL = pLnL ? nL : 0; + const sal_Int32 nT2BB = pLnB ? nB : 0; + const sal_Int32 nT2BR = pLnR ? nR : 0; + + // Resulting distances from edge to borders + const sal_Int32 nE2BT = pLnT ? std::max<sal_Int32>(rMargins.nTop - nT - nWidthT, 0) : 0; + const sal_Int32 nE2BL = pLnL ? std::max<sal_Int32>(rMargins.nLeft - nL - nWidthL, 0) : 0; + const sal_Int32 nE2BB = pLnB ? std::max<sal_Int32>(rMargins.nBottom - nB - nWidthB, 0) : 0; + const sal_Int32 nE2BR = pLnR ? std::max<sal_Int32>(rMargins.nRight - nR - nWidthR, 0) : 0; + + const sal_Int32 n32pt = 32 * 20; + // 1. If all borders are in range of 31 pts from text + if (nT2BT < n32pt && nT2BL < n32pt && nT2BB < n32pt && nT2BR < n32pt) + { + rDistances.bFromEdge = false; + } + else + { + // 2. If all borders are in range of 31 pts from edge + if (nE2BT < n32pt && nE2BL < n32pt && nE2BB < n32pt && nE2BR < n32pt) + { + rDistances.bFromEdge = true; + } + else + { + // Let's try to guess which would be the best approximation + rDistances.bFromEdge = + (nT2BT + nT2BL + nT2BB + nT2BR) > (nE2BT + nE2BL + nE2BB + nE2BR); + } + } + + if (rDistances.bFromEdge) + { + rDistances.nTop = sal::static_int_cast<sal_uInt16>(nE2BT); + rDistances.nLeft = sal::static_int_cast<sal_uInt16>(nE2BL); + rDistances.nBottom = sal::static_int_cast<sal_uInt16>(nE2BB); + rDistances.nRight = sal::static_int_cast<sal_uInt16>(nE2BR); + } + else + { + rDistances.nTop = sal::static_int_cast<sal_uInt16>(nT2BT); + rDistances.nLeft = sal::static_int_cast<sal_uInt16>(nT2BL); + rDistances.nBottom = sal::static_int_cast<sal_uInt16>(nT2BB); + rDistances.nRight = sal::static_int_cast<sal_uInt16>(nT2BR); + } +} + +} + // class SvxFormatBreakItem ------------------------------------------------- bool SvxFormatBreakItem::operator==( const SfxPoolItem& rAttr ) const |