diff options
-rw-r--r-- | editeng/source/items/frmitems.cxx | 125 | ||||
-rw-r--r-- | include/editeng/boxitem.hxx | 30 | ||||
-rw-r--r-- | sw/qa/extras/ooxmlexport/data/tdf112118.docx | bin | 11698 -> 11672 bytes | |||
-rw-r--r-- | sw/qa/extras/ooxmlexport/ooxmlexport11.cxx | 2 | ||||
-rw-r--r-- | sw/qa/extras/ww8export/data/tdf112118.doc | bin | 0 -> 27136 bytes | |||
-rw-r--r-- | sw/qa/extras/ww8export/ww8export2.cxx | 31 | ||||
-rw-r--r-- | sw/source/filter/ww8/docxattributeoutput.cxx | 131 | ||||
-rw-r--r-- | sw/source/filter/ww8/docxattributeoutput.hxx | 21 | ||||
-rw-r--r-- | sw/source/filter/ww8/wrtw8sty.cxx | 4 | ||||
-rw-r--r-- | sw/source/filter/ww8/ww8atr.cxx | 40 | ||||
-rw-r--r-- | sw/source/filter/ww8/ww8attributeoutput.hxx | 6 | ||||
-rw-r--r-- | sw/source/filter/ww8/ww8par6.cxx | 81 | ||||
-rw-r--r-- | writerfilter/source/dmapper/PropertyMap.cxx | 36 |
13 files changed, 273 insertions, 234 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 diff --git a/include/editeng/boxitem.hxx b/include/editeng/boxitem.hxx index e6ebd6d42379..14a30dfc4c70 100644 --- a/include/editeng/boxitem.hxx +++ b/include/editeng/boxitem.hxx @@ -231,6 +231,36 @@ public: : ( nValidFlags &= ~nValid ); } void ResetFlags(); }; + +namespace editeng +{ + +void EDITENG_DLLPUBLIC BorderDistanceFromWord(bool bFromEdge, sal_Int32& nMargin, + sal_Int32& nBorderDistance, sal_Int32 nBorderWidth); + +struct EDITENG_DLLPUBLIC WordPageMargins final +{ + sal_uInt16 nLeft = 0; + sal_uInt16 nRight = 0; + sal_uInt16 nTop = 0; + sal_uInt16 nBottom = 0; +}; + +struct EDITENG_DLLPUBLIC WordBorderDistances final +{ + bool bFromEdge = false; + sal_uInt16 nLeft = 0; + sal_uInt16 nRight = 0; + sal_uInt16 nTop = 0; + sal_uInt16 nBottom = 0; +}; + +// Heuristics to decide if we need to use "from edge" offset of borders. All sizes in twips +void EDITENG_DLLPUBLIC BorderDistancesToWord(const SvxBoxItem& rBox, const WordPageMargins& rMargins, + WordBorderDistances& rDistances); + +} + #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/qa/extras/ooxmlexport/data/tdf112118.docx b/sw/qa/extras/ooxmlexport/data/tdf112118.docx Binary files differindex 87081d8c6dd9..dc3e14ae82c7 100644 --- a/sw/qa/extras/ooxmlexport/data/tdf112118.docx +++ 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 239786d5f8eb..ba89b63b2f6e 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx @@ -281,7 +281,7 @@ DECLARE_OOXMLEXPORT_TEST(testTdf107035, "tdf107035.docx") CPPUNIT_ASSERT_EQUAL(sal_Int32(COL_AUTO), nPgNumColour); } -DECLARE_OOXMLEXPORT_TEST(testTdf112118, "tdf112118.docx") +DECLARE_OOXMLEXPORT_TEST(testTdf112118_DOCX, "tdf112118.docx") { auto xStyles = getStyles("PageStyles"); auto testProc = [&](const OUString& sStyleName, sal_Int32 nMargin, sal_Int32 nBorderDistance, diff --git a/sw/qa/extras/ww8export/data/tdf112118.doc b/sw/qa/extras/ww8export/data/tdf112118.doc Binary files differnew file mode 100644 index 000000000000..3c8e256407ad --- /dev/null +++ b/sw/qa/extras/ww8export/data/tdf112118.doc diff --git a/sw/qa/extras/ww8export/ww8export2.cxx b/sw/qa/extras/ww8export/ww8export2.cxx index 3d977881c677..4bb2947aef78 100644 --- a/sw/qa/extras/ww8export/ww8export2.cxx +++ b/sw/qa/extras/ww8export/ww8export2.cxx @@ -741,6 +741,37 @@ DECLARE_OOXMLEXPORT_TEST( testObjectCrossReference, "object_cross_reference.odt" } } +DECLARE_WW8EXPORT_TEST(testTdf112118_DOC, "tdf112118.doc") +{ + 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("Convert 1", 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 d4cf4c8f29c4..fd8750dfb1ac 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -74,7 +74,6 @@ #include <editeng/colritem.hxx> #include <editeng/hyphenzoneitem.hxx> #include <editeng/ulspitem.hxx> -#include <editeng/boxitem.hxx> #include <editeng/contouritem.hxx> #include <editeng/shdditem.hxx> #include <editeng/emphasismarkitem.hxx> @@ -3066,98 +3065,6 @@ static OutputBorderOptions lcl_getBoxBorderOptions() return rOptions; } -struct BorderDistances -{ - 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 distorted 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, std::map<SvxBoxItemLine, css::table::BorderLine2> &rTableStyleConf ) { @@ -6143,15 +6050,16 @@ void DocxAttributeOutput::SectionPageBorders( const SwFrameFormat* pFormat, cons } // By top margin, impl_borders() means the distance between the top of the page and the header frame. - PageMargins aMargins = m_pageMargins; + editeng::WordPageMargins aMargins = m_pageMargins; HdFtDistanceGlue aGlue(pFormat->GetAttrSet()); if (aGlue.HasHeader()) - aMargins.nPageMarginTop = aGlue.dyaHdrTop; + aMargins.nTop = aGlue.dyaHdrTop; // Ditto for bottom margin. if (aGlue.HasFooter()) - aMargins.nPageMarginBottom = aGlue.dyaHdrBottom; + aMargins.nBottom = aGlue.dyaHdrBottom; - CalculateExportDistances(rBox, aMargins, aOutputBorderOptions); + aOutputBorderOptions.pDistances = std::make_shared<editeng::WordBorderDistances>(); + editeng::BorderDistancesToWord(rBox, aMargins, *aOutputBorderOptions.pDistances); // All distances are relative to the text margins m_pSerializer->startElementNS(XML_w, XML_pgBorders, @@ -7993,24 +7901,21 @@ void DocxAttributeOutput::FormatLRSpace( const SvxLRSpaceItem& rLRSpace ) } else if ( m_rExport.m_bOutPageDescs ) { - m_pageMargins.nPageMarginLeft = 0; - m_pageMargins.nPageMarginRight = 0; + m_pageMargins.nLeft = 0; + m_pageMargins.nRight = 0; - const SfxPoolItem* pItem = m_rExport.HasItem( RES_BOX ); - if ( pItem ) + if ( auto pBoxItem = static_cast<const SvxBoxItem*>(m_rExport.HasItem( RES_BOX )) ) { - m_pageMargins.nPageMarginRight = static_cast<const SvxBoxItem*>(pItem)->CalcLineSpace( SvxBoxItemLine::LEFT, /*bEvenIfNoLine*/true ); - m_pageMargins.nPageMarginLeft = static_cast<const SvxBoxItem*>(pItem)->CalcLineSpace( SvxBoxItemLine::RIGHT, /*bEvenIfNoLine*/true ); + m_pageMargins.nRight = pBoxItem->CalcLineSpace( SvxBoxItemLine::LEFT, /*bEvenIfNoLine*/true ); + m_pageMargins.nLeft = pBoxItem->CalcLineSpace( SvxBoxItemLine::RIGHT, /*bEvenIfNoLine*/true ); } - else - m_pageMargins.nPageMarginLeft = m_pageMargins.nPageMarginRight = 0; - m_pageMargins.nPageMarginLeft = m_pageMargins.nPageMarginLeft + static_cast<sal_uInt16>(rLRSpace.GetLeft()); - m_pageMargins.nPageMarginRight = m_pageMargins.nPageMarginRight + static_cast<sal_uInt16>(rLRSpace.GetRight()); + m_pageMargins.nLeft += sal::static_int_cast<sal_uInt16>(rLRSpace.GetLeft()); + m_pageMargins.nRight += sal::static_int_cast<sal_uInt16>(rLRSpace.GetRight()); AddToAttrList( m_pSectionSpacingAttrList, 2, - FSNS( XML_w, XML_left ), OString::number( m_pageMargins.nPageMarginLeft ).getStr(), - FSNS( XML_w, XML_right ), OString::number( m_pageMargins.nPageMarginRight ).getStr() ); + FSNS( XML_w, XML_left ), OString::number( m_pageMargins.nLeft ).getStr(), + FSNS( XML_w, XML_right ), OString::number( m_pageMargins.nRight ).getStr() ); } else { @@ -8062,20 +7967,20 @@ void DocxAttributeOutput::FormatULSpace( const SvxULSpaceItem& rULSpace ) nHeader = sal_Int32( aDistances.dyaHdrTop ); // Page top - m_pageMargins.nPageMarginTop = aDistances.dyaTop; + m_pageMargins.nTop = aDistances.dyaTop; sal_Int32 nFooter = 0; if ( aDistances.HasFooter() ) nFooter = sal_Int32( aDistances.dyaHdrBottom ); // Page Bottom - m_pageMargins.nPageMarginBottom = aDistances.dyaBottom; + m_pageMargins.nBottom = aDistances.dyaBottom; AddToAttrList( m_pSectionSpacingAttrList, 5, FSNS( XML_w, XML_header ), OString::number( nHeader ).getStr(), - FSNS( XML_w, XML_top ), OString::number( m_pageMargins.nPageMarginTop ).getStr(), + FSNS( XML_w, XML_top ), OString::number( m_pageMargins.nTop ).getStr(), FSNS( XML_w, XML_footer ), OString::number( nFooter ).getStr(), - FSNS( XML_w, XML_bottom ), OString::number( m_pageMargins.nPageMarginBottom ).getStr(), + FSNS( XML_w, XML_bottom ), OString::number( m_pageMargins.nBottom ).getStr(), // FIXME Page Gutter is not handled ATM, setting to 0 as it's mandatory for OOXML FSNS( XML_w, XML_gutter ), "0" ); } diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx index 887976a53931..4d380bf6e656 100644 --- a/sw/source/filter/ww8/docxattributeoutput.hxx +++ b/sw/source/filter/ww8/docxattributeoutput.hxx @@ -27,6 +27,7 @@ #include <IMark.hxx> #include "docxexport.hxx" +#include <editeng/boxitem.hxx> #include <sax/fshelper.hxx> #include <sax/fastattribs.hxx> #include <vcl/vclenum.hxx> @@ -68,8 +69,6 @@ enum DocxColBreakStatus COLBRK_WRITE }; -struct BorderDistances; - /** * A structure that holds information about the options selected * when outputting a border to DOCX. @@ -88,21 +87,7 @@ struct OutputBorderOptions bool bWriteInsideHV = false; bool bWriteDistance = false; SvxShadowLocation aShadowLocation = SvxShadowLocation::NONE; - std::shared_ptr<BorderDistances> pDistances; -}; - -/** - * A structure that holds information about the page margins. - * - */ -struct PageMargins -{ - sal_uInt16 nPageMarginLeft; - sal_uInt16 nPageMarginRight; - sal_uInt16 nPageMarginTop; - sal_uInt16 nPageMarginBottom; - - PageMargins() : nPageMarginLeft(0), nPageMarginRight(0), nPageMarginTop(0), nPageMarginBottom(0) {} + std::shared_ptr<editeng::WordBorderDistances> pDistances; }; struct DocxTableExportContext; @@ -929,7 +914,7 @@ private: /// Is fake rotation detected, so rotation with 90 degrees should be ignored in this cell? bool m_bBtLr; - PageMargins m_pageMargins; + editeng::WordPageMargins m_pageMargins; std::shared_ptr<DocxTableStyleExport> m_pTableStyleExport; // flag to check if auto spacing was set in original file diff --git a/sw/source/filter/ww8/wrtw8sty.cxx b/sw/source/filter/ww8/wrtw8sty.cxx index 5cc7bc335008..3505d8f641e3 100644 --- a/sw/source/filter/ww8/wrtw8sty.cxx +++ b/sw/source/filter/ww8/wrtw8sty.cxx @@ -1392,6 +1392,10 @@ void WW8AttributeOutput::SectionPageBorders( const SwFrameFormat* pPdFormat, con nPgBorder = 2; } + // [MS-DOC] 2.9.255 SPgbPropOperand; 2.9.185 PgbOffsetFrom + if (m_bFromEdge) + nPgBorder |= (1<<5); + if ( USHRT_MAX != nPgBorder ) { // write the Flag and Border Attribute diff --git a/sw/source/filter/ww8/ww8atr.cxx b/sw/source/filter/ww8/ww8atr.cxx index f6c40194bf5e..9f1419f75209 100644 --- a/sw/source/filter/ww8/ww8atr.cxx +++ b/sw/source/filter/ww8/ww8atr.cxx @@ -3959,25 +3959,25 @@ void WW8AttributeOutput::FormatLRSpace( const SvxLRSpaceItem& rLR ) } else if ( m_rWW8Export.m_bOutPageDescs ) // PageDescs { - sal_uInt16 nLDist, nRDist; - const SfxPoolItem* pItem = m_rWW8Export.HasItem( RES_BOX ); - if ( pItem ) + m_pageMargins.nLeft = 0; + m_pageMargins.nRight = 0; + + if ( auto pBoxItem = static_cast<const SvxBoxItem*>(m_rWW8Export.HasItem( RES_BOX )) ) { - nRDist = static_cast<const SvxBoxItem*>(pItem)->CalcLineSpace( SvxBoxItemLine::LEFT, /*bEvenIfNoLine*/true ); - nLDist = static_cast<const SvxBoxItem*>(pItem)->CalcLineSpace( SvxBoxItemLine::RIGHT, /*bEvenIfNoLine*/true ); + m_pageMargins.nRight = pBoxItem->CalcLineSpace( SvxBoxItemLine::LEFT, /*bEvenIfNoLine*/true ); + m_pageMargins.nLeft = pBoxItem->CalcLineSpace( SvxBoxItemLine::RIGHT, /*bEvenIfNoLine*/true ); } - else - nLDist = nRDist = 0; - nLDist = nLDist + static_cast<sal_uInt16>(rLR.GetLeft()); - nRDist = nRDist + static_cast<sal_uInt16>(rLR.GetRight()); + + m_pageMargins.nLeft += sal::static_int_cast<sal_uInt16>(rLR.GetLeft()); + m_pageMargins.nRight += sal::static_int_cast<sal_uInt16>(rLR.GetRight()); // sprmSDxaLeft m_rWW8Export.InsUInt16( NS_sprm::sprmSDxaLeft ); - m_rWW8Export.InsUInt16( nLDist ); + m_rWW8Export.InsUInt16( m_pageMargins.nLeft ); // sprmSDxaRight m_rWW8Export.InsUInt16( NS_sprm::sprmSDxaRight ); - m_rWW8Export.InsUInt16( nRDist ); + m_rWW8Export.InsUInt16( m_pageMargins.nRight ); } else { // normal paragraphs @@ -4024,6 +4024,7 @@ void WW8AttributeOutput::FormatULSpace( const SvxULSpaceItem& rUL ) // sprmSDyaTop m_rWW8Export.InsUInt16( NS_sprm::sprmSDyaTop ); m_rWW8Export.InsUInt16( aDistances.dyaTop ); + m_pageMargins.nTop = aDistances.dyaTop; if ( aDistances.HasFooter() ) { @@ -4035,6 +4036,7 @@ void WW8AttributeOutput::FormatULSpace( const SvxULSpaceItem& rUL ) //sprmSDyaBottom m_rWW8Export.InsUInt16( NS_sprm::sprmSDyaBottom ); m_rWW8Export.InsUInt16( aDistances.dyaBottom ); + m_pageMargins.nBottom = aDistances.dyaBottom; } else { @@ -4461,7 +4463,21 @@ void WW8AttributeOutput::FormatBox( const SvxBoxItem& rBox ) && ( p->GetWidth() != 0 ); } - m_rWW8Export.Out_SwFormatBox( rBox, bShadow ); + SvxBoxItem aBox(rBox); + if (m_rWW8Export.m_bOutPageDescs) + { + editeng::WordBorderDistances aDistances; + editeng::BorderDistancesToWord(aBox, m_pageMargins, aDistances); + + aBox.SetDistance(aDistances.nTop, SvxBoxItemLine::TOP); + aBox.SetDistance(aDistances.nLeft, SvxBoxItemLine::LEFT); + aBox.SetDistance(aDistances.nBottom, SvxBoxItemLine::BOTTOM); + aBox.SetDistance(aDistances.nRight, SvxBoxItemLine::RIGHT); + + m_bFromEdge = aDistances.bFromEdge; + } + + m_rWW8Export.Out_SwFormatBox( aBox, bShadow ); } } diff --git a/sw/source/filter/ww8/ww8attributeoutput.hxx b/sw/source/filter/ww8/ww8attributeoutput.hxx index cf47f534d9e6..d42c97511303 100644 --- a/sw/source/filter/ww8/ww8attributeoutput.hxx +++ b/sw/source/filter/ww8/ww8attributeoutput.hxx @@ -22,6 +22,7 @@ #include "attributeoutputbase.hxx" #include "wrtww8.hxx" +#include <editeng/boxitem.hxx> class WW8AttributeOutput : public AttributeOutputBase { @@ -491,6 +492,11 @@ protected: void TableCellBorders( ww8::WW8TableNodeInfoInner::Pointer_t const & pTableTextNodeInfoInner ); +private: + + editeng::WordPageMargins m_pageMargins; + bool m_bFromEdge = false; + }; #endif // INCLUDED_SW_SOURCE_FILTER_WW8_WW8ATTRIBUTEOUTPUT_HXX diff --git a/sw/source/filter/ww8/ww8par6.cxx b/sw/source/filter/ww8/ww8par6.cxx index b088f86e5c4d..5e8341e88060 100644 --- a/sw/source/filter/ww8/ww8par6.cxx +++ b/sw/source/filter/ww8/ww8par6.cxx @@ -430,11 +430,22 @@ void wwSectionManager::SetPage(SwPageDesc &rInPageDesc, SwFrameFormat &rFormat, SetCols(rFormat, rSection, rSection.GetTextAreaWidth()); } -static sal_uInt16 lcl_MakeSafeNegativeSpacing(sal_uInt16 nIn) +namespace { +// Returns corrected (ODF) margin size +long SetBorderDistance(bool bFromEdge, SvxBoxItem& aBox, SvxBoxItemLine eLine, long nMSMargin) { - if (nIn > SHRT_MAX) - nIn = 0; - return nIn; + const editeng::SvxBorderLine* pLine = aBox.GetLine(eLine); + if (!pLine) + return nMSMargin; + sal_Int32 nNewMargin = nMSMargin; + sal_Int32 nNewDist = aBox.GetDistance(eLine); + sal_Int32 nLineWidth = pLine->GetWidth(); + + editeng::BorderDistanceFromWord(bFromEdge, nNewMargin, nNewDist, nLineWidth); + aBox.SetDistance(nNewDist, eLine); + + return nNewMargin; +} } void SwWW8ImplReader::SetPageBorder(SwFrameFormat &rFormat, const wwSection &rSection) @@ -447,65 +458,15 @@ void SwWW8ImplReader::SetPageBorder(SwFrameFormat &rFormat, const wwSection &rSe SetFlyBordersShadow(aSet, rSection.brc, &aSizeArray[0]); SvxLRSpaceItem aLR(ItemGet<SvxLRSpaceItem>(aSet, RES_LR_SPACE)); SvxULSpaceItem aUL(ItemGet<SvxULSpaceItem>(aSet, RES_UL_SPACE)); - SvxBoxItem aBox(ItemGet<SvxBoxItem>(aSet, RES_BOX)); - short aOriginalBottomMargin = aBox.GetDistance(SvxBoxItemLine::BOTTOM); - - if (rSection.maSep.pgbOffsetFrom == 1) - { - sal_uInt16 nDist; - if (aBox.GetLeft()) - { - nDist = aBox.GetDistance(SvxBoxItemLine::LEFT); - aBox.SetDistance(lcl_MakeSafeNegativeSpacing(static_cast<sal_uInt16>(aLR.GetLeft() - nDist)), SvxBoxItemLine::LEFT); - aSizeArray[WW8_LEFT] = - aSizeArray[WW8_LEFT] - nDist + aBox.GetDistance(SvxBoxItemLine::LEFT); - } - - if (aBox.GetRight()) - { - nDist = aBox.GetDistance(SvxBoxItemLine::RIGHT); - aBox.SetDistance(lcl_MakeSafeNegativeSpacing(static_cast<sal_uInt16>(aLR.GetRight() - nDist)), SvxBoxItemLine::RIGHT); - aSizeArray[WW8_RIGHT] = - aSizeArray[WW8_RIGHT] - nDist + aBox.GetDistance(SvxBoxItemLine::RIGHT); - } + bool bFromEdge = rSection.maSep.pgbOffsetFrom == 1; - if (aBox.GetTop()) - { - nDist = aBox.GetDistance(SvxBoxItemLine::TOP); - aBox.SetDistance(lcl_MakeSafeNegativeSpacing(static_cast<sal_uInt16>(aUL.GetUpper() - nDist)), SvxBoxItemLine::TOP); - aSizeArray[WW8_TOP] = - aSizeArray[WW8_TOP] - nDist + aBox.GetDistance(SvxBoxItemLine::TOP); - } - - if (aBox.GetBottom()) - { - nDist = aBox.GetDistance(SvxBoxItemLine::BOTTOM); - aBox.SetDistance(lcl_MakeSafeNegativeSpacing(static_cast<sal_uInt16>(aUL.GetLower() - nDist)), SvxBoxItemLine::BOTTOM); - aSizeArray[WW8_BOT] = - aSizeArray[WW8_BOT] - nDist + aBox.GetDistance(SvxBoxItemLine::BOTTOM); - } - - aSet.Put(aBox); - } - - if (aBox.GetLeft()) - aLR.SetLeft(lcl_MakeSafeNegativeSpacing(static_cast<sal_uInt16>(aLR.GetLeft() - aSizeArray[WW8_LEFT]))); - if (aBox.GetRight()) - aLR.SetRight(lcl_MakeSafeNegativeSpacing(static_cast<sal_uInt16>(aLR.GetRight() - aSizeArray[WW8_RIGHT]))); - if (aBox.GetTop()) - aUL.SetUpper(lcl_MakeSafeNegativeSpacing(static_cast<sal_uInt16>(aUL.GetUpper() - aSizeArray[WW8_TOP]))); - if (aBox.GetBottom()) - { - //#i30088# and #i30074# - do a final sanity check on - //bottom value. Do not allow a resulting zero if bottom - //Border margin value was not originally zero. - if(aUL.GetLower() != 0) - aUL.SetLower(lcl_MakeSafeNegativeSpacing(static_cast<sal_uInt16>(aUL.GetLower() - aSizeArray[WW8_BOT]))); - else - aUL.SetLower(lcl_MakeSafeNegativeSpacing(static_cast<sal_uInt16>(aOriginalBottomMargin - aSizeArray[WW8_BOT]))); - } + aLR.SetLeft(SetBorderDistance(bFromEdge, aBox, SvxBoxItemLine::LEFT, aLR.GetLeft())); + aLR.SetRight(SetBorderDistance(bFromEdge, aBox, SvxBoxItemLine::RIGHT, aLR.GetRight())); + aUL.SetUpper(SetBorderDistance(bFromEdge, aBox, SvxBoxItemLine::TOP, aUL.GetUpper())); + aUL.SetLower(SetBorderDistance(bFromEdge, aBox, SvxBoxItemLine::BOTTOM, aUL.GetLower())); + aSet.Put(aBox); aSet.Put(aLR); aSet.Put(aUL); rFormat.SetFormatAttr(aSet); diff --git a/writerfilter/source/dmapper/PropertyMap.cxx b/writerfilter/source/dmapper/PropertyMap.cxx index 2447ee40aeb9..76851c428438 100644 --- a/writerfilter/source/dmapper/PropertyMap.cxx +++ b/writerfilter/source/dmapper/PropertyMap.cxx @@ -20,6 +20,7 @@ #include <ooxml/resourceids.hxx> #include "DomainMapper_Impl.hxx" #include "ConversionHelper.hxx" +#include <editeng/boxitem.hxx> #include <i18nutil/paper.hxx> #include <osl/diagnose.h> #include <rtl/ustring.hxx> @@ -647,8 +648,6 @@ void SectionPropertyMap::SetBorderDistance( const uno::Reference< beans::XProper BorderOffsetFrom eOffsetFrom, sal_uInt32 nLineWidth ) { - // See https://wiki.openoffice.org/wiki/Writer/MSInteroperability/PageBorder - if (!xStyle.is()) return; const OUString sMarginName = getPropertyName( eMarginId ); @@ -656,35 +655,12 @@ void SectionPropertyMap::SetBorderDistance( const uno::Reference< beans::XProper 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 correct 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; - } + editeng::BorderDistanceFromWord(eOffsetFrom == BorderOffsetFrom::Edge, nMargin, nDistance, + nLineWidth); + // Change the margins with the border distance - xStyle->setPropertyValue( sMarginName, uno::makeAny( nNewMargin ) ); - xStyle->setPropertyValue( sBorderDistanceName, uno::makeAny( nNewDist ) ); + xStyle->setPropertyValue( sMarginName, uno::makeAny( nMargin ) ); + xStyle->setPropertyValue( sBorderDistanceName, uno::makeAny( nDistance ) ); } void SectionPropertyMap::DontBalanceTextColumns() |