desktop/source/deployment/dp_persmap.cxx | 5 editeng/source/items/frmitems.cxx | 68 ++++++--- include/editeng/boxitem.hxx | 15 +- sw/ooxmlexport_setup.mk | 1 sw/qa/core/layout/layout.cxx | 71 ++++++++++ sw/qa/extras/ooxmlexport/ooxmlexport17.cxx | 42 +++++ sw/qa/extras/ww8import/ww8import.cxx | 4 sw/source/core/layout/paintfrm.cxx | 4 sw/source/filter/ww8/wrtww8.cxx | 2 sw/source/uibase/shells/tabsh.cxx | 2 writerfilter/qa/cppunittests/dmapper/PropertyMap.cxx | 60 ++++++++ writerfilter/qa/cppunittests/dmapper/data/negative-page-border-no-margin.docx |binary writerfilter/qa/cppunittests/dmapper/data/negative-page-border.docx |binary writerfilter/source/dmapper/PropertyMap.cxx | 2 14 files changed, 239 insertions(+), 37 deletions(-)
New commits: commit 1f127a2b9e1c1daab0972f98fc8708ecb7afa299 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Tue Jun 7 08:03:34 2022 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Tue Jun 7 08:45:46 2022 +0200 sw layout: allow negative page border distances Writer follows the CSS box model when it comes to page borders: there can be a positive distance between the edge of the page and the border, and again a positive distance between the border and the body frame. This ensures that the page border never intersect with the body frame, which is usually what users expect. Word, however, can work with 2 distances for border and text, both measured from the edge of the page, leading to a page border, which is inside the body text. This is described at great detail at <https://wiki.openoffice.org/wiki/Writer/MSInteroperability/PageBorder#Importing_case_3:>. Fix the problem by allowing negative border distances: this doesn't influence the position or the size of the body frame, but it gives us a way to position the border more towards the center of the page, leading the matching layout between Writer and Word. The doc model (to allow negative border distances), UNO API and DOCX filter is updated in this commit. The ODT filter works without explicit effort. Other filters are not yet updated in this commit. Change-Id: I723e1bdb8dc6391129f1686f88826cc089f6fd67 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135462 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins diff --git a/editeng/source/items/frmitems.cxx b/editeng/source/items/frmitems.cxx index a31df88ca0f0..9780af4904c0 100644 --- a/editeng/source/items/frmitems.cxx +++ b/editeng/source/items/frmitems.cxx @@ -1313,6 +1313,20 @@ SvxBoxItem::~SvxBoxItem() { } +void SvxBoxItem::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SvxBoxItem")); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("top-dist"), + BAD_CAST(OString::number(nTopDist).getStr())); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("bottom-dist"), + BAD_CAST(OString::number(nBottomDist).getStr())); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("left-dist"), + BAD_CAST(OString::number(nLeftDist).getStr())); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("right-dist"), + BAD_CAST(OString::number(nRightDist).getStr())); + SfxPoolItem::dumpAsXml(pWriter); + (void)xmlTextWriterEndElement(pWriter); +} boost::property_tree::ptree SvxBoxItem::dumpAsJSON() const { @@ -1380,7 +1394,7 @@ bool SvxBoxItem::QueryValue( uno::Any& rVal, sal_uInt8 nMemberId ) const { bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); table::BorderLine2 aRetLine; - sal_uInt16 nDist = 0; + sal_Int16 nDist = 0; bool bDistMember = false; nMemberId &= ~CONVERT_TWIPS; switch(nMemberId) @@ -1670,7 +1684,6 @@ bool SvxBoxItem::PutValue( const uno::Any& rVal, sal_uInt8 nMemberId ) if(!(rVal >>= nDist)) return false; - if(nDist >= 0) { if( bConvert ) nDist = o3tl::toTwips(nDist, o3tl::Length::mm100); @@ -1883,10 +1896,10 @@ void SvxBoxItem::ScaleMetrics( tools::Long nMult, tools::Long nDiv ) if ( pBottom ) pBottom->ScaleMetrics( nMult, nDiv ); if ( pLeft ) pLeft->ScaleMetrics( nMult, nDiv ); if ( pRight ) pRight->ScaleMetrics( nMult, nDiv ); - nTopDist = static_cast<sal_uInt16>(BigInt::Scale( nTopDist, nMult, nDiv )); - nBottomDist = static_cast<sal_uInt16>(BigInt::Scale( nBottomDist, nMult, nDiv )); - nLeftDist = static_cast<sal_uInt16>(BigInt::Scale( nLeftDist, nMult, nDiv )); - nRightDist = static_cast<sal_uInt16>(BigInt::Scale( nRightDist, nMult, nDiv )); + nTopDist = static_cast<sal_Int16>(BigInt::Scale( nTopDist, nMult, nDiv )); + nBottomDist = static_cast<sal_Int16>(BigInt::Scale( nBottomDist, nMult, nDiv )); + nLeftDist = static_cast<sal_Int16>(BigInt::Scale( nLeftDist, nMult, nDiv )); + nRightDist = static_cast<sal_Int16>(BigInt::Scale( nRightDist, nMult, nDiv )); } @@ -1962,9 +1975,9 @@ sal_uInt16 SvxBoxItem::GetSmallestDistance() const } -sal_uInt16 SvxBoxItem::GetDistance( SvxBoxItemLine nLine ) const +sal_Int16 SvxBoxItem::GetDistance( SvxBoxItemLine nLine, bool bAllowNegative ) const { - sal_uInt16 nDist = 0; + sal_Int16 nDist = 0; switch ( nLine ) { case SvxBoxItemLine::TOP: @@ -1983,11 +1996,15 @@ sal_uInt16 SvxBoxItem::GetDistance( SvxBoxItemLine nLine ) const OSL_FAIL( "wrong line" ); } + if (!bAllowNegative && nDist < 0) + { + nDist = 0; + } return nDist; } -void SvxBoxItem::SetDistance( sal_uInt16 nNew, SvxBoxItemLine nLine ) +void SvxBoxItem::SetDistance( sal_Int16 nNew, SvxBoxItemLine nLine ) { switch ( nLine ) { @@ -2036,10 +2053,10 @@ sal_uInt16 SvxBoxItem::CalcLineWidth( SvxBoxItemLine nLine ) const return nWidth; } -sal_uInt16 SvxBoxItem::CalcLineSpace( SvxBoxItemLine nLine, bool bEvenIfNoLine ) const +sal_Int16 SvxBoxItem::CalcLineSpace( SvxBoxItemLine nLine, bool bEvenIfNoLine, bool bAllowNegative ) const { SvxBorderLine* pTmp = nullptr; - sal_uInt16 nDist = 0; + sal_Int16 nDist = 0; switch ( nLine ) { case SvxBoxItemLine::TOP: @@ -2068,6 +2085,12 @@ sal_uInt16 SvxBoxItem::CalcLineSpace( SvxBoxItemLine nLine, bool bEvenIfNoLine ) } else if( !bEvenIfNoLine ) nDist = 0; + + if (!bAllowNegative && nDist < 0) + { + nDist = 0; + } + return nDist; } @@ -2429,7 +2452,7 @@ namespace editeng { void BorderDistanceFromWord(bool bFromEdge, sal_Int32& nMargin, sal_Int32& nBorderDistance, - sal_Int32 nBorderWidth) + sal_Int32 nBorderWidth, bool bAllowNegativeBorderDistance) { // See https://wiki.openoffice.org/wiki/Writer/MSInteroperability/PageBorder @@ -2456,8 +2479,15 @@ void BorderDistanceFromWord(bool bFromEdge, sal_Int32& nMargin, sal_Int32& nBord } else if (nNewBorderDistance < 0) { - nNewMargin = std::max<sal_Int32>(nMargin - nBorderWidth, 0); - nNewBorderDistance = 0; + if (bAllowNegativeBorderDistance) + { + nNewMargin = nMargin; + } + else + { + nNewMargin = std::max<sal_Int32>(nMargin - nBorderWidth, 0); + nNewBorderDistance = 0; + } } nMargin = nNewMargin; @@ -2481,10 +2511,10 @@ void BorderDistancesToWord(const SvxBoxItem& rBox, const WordPageMargins& rMargi WordBorderDistances& rDistances) { // Use signed sal_Int32 that can hold sal_uInt16, to prevent overflow at subtraction 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); + const sal_Int32 nT = rBox.GetDistance(SvxBoxItemLine::TOP, /*bAllowNegative=*/true); + const sal_Int32 nL = rBox.GetDistance(SvxBoxItemLine::LEFT, /*bAllowNegative=*/true); + const sal_Int32 nB = rBox.GetDistance(SvxBoxItemLine::BOTTOM, /*bAllowNegative=*/true); + const sal_Int32 nR = rBox.GetDistance(SvxBoxItemLine::RIGHT, /*bAllowNegative=*/true); // Only take into account existing borders const SvxBorderLine* pLnT = rBox.GetLine(SvxBoxItemLine::TOP); @@ -2512,7 +2542,7 @@ void BorderDistancesToWord(const SvxBoxItem& rBox, const WordPageMargins& rMargi 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) + if (nT2BT >= 0 && nT2BT < n32pt && nT2BL >= 0 && nT2BL < n32pt && nT2BB >= 0 && nT2BB < n32pt && nT2BR >= 0 && nT2BR < n32pt) { rDistances.bFromEdge = false; } diff --git a/include/editeng/boxitem.hxx b/include/editeng/boxitem.hxx index 6e0fc53d080c..750993c91f7d 100644 --- a/include/editeng/boxitem.hxx +++ b/include/editeng/boxitem.hxx @@ -59,7 +59,7 @@ class EDITENG_DLLPUBLIC SvxBoxItem final : public SfxPoolItem pBottom, pLeft, pRight; - sal_uInt16 nTopDist, + sal_Int16 nTopDist, nBottomDist, nLeftDist, nRightDist; @@ -97,29 +97,30 @@ public: //The Pointers are being copied! void SetLine( const editeng::SvxBorderLine* pNew, SvxBoxItemLine nLine ); - sal_uInt16 GetDistance( SvxBoxItemLine nLine ) const; + sal_Int16 GetDistance( SvxBoxItemLine nLine, bool bAllowNegative = false ) const; sal_uInt16 GetSmallestDistance() const; bool IsRemoveAdjacentCellBorder() const { return bRemoveAdjCellBorder; } - void SetDistance( sal_uInt16 nNew, SvxBoxItemLine nLine ); - inline void SetAllDistances( sal_uInt16 nNew ); + void SetDistance( sal_Int16 nNew, SvxBoxItemLine nLine ); + inline void SetAllDistances( sal_Int16 nNew ); void SetRemoveAdjacentCellBorder( bool bSet ) { bRemoveAdjCellBorder = bSet; } // Line width plus Space plus inward distance // bEvenIfNoLine = TRUE -> Also return distance, when no Line is set sal_uInt16 CalcLineWidth( SvxBoxItemLine nLine ) const; - sal_uInt16 CalcLineSpace( SvxBoxItemLine nLine, bool bEvenIfNoLine = false ) const; + sal_Int16 CalcLineSpace( SvxBoxItemLine nLine, bool bEvenIfNoLine = false, bool bAllowNegative = false ) const; bool HasBorder( bool bTreatPaddingAsBorder ) const; static css::table::BorderLine2 SvxLineToLine( const editeng::SvxBorderLine* pLine, bool bConvert ); static bool LineToSvxLine(const css::table::BorderLine& rLine, editeng::SvxBorderLine& rSvxLine, bool bConvert); static bool LineToSvxLine(const css::table::BorderLine2& rLine, editeng::SvxBorderLine& rSvxLine, bool bConvert); virtual boost::property_tree::ptree dumpAsJSON() const override; + void dumpAsXml(xmlTextWriterPtr pWriter) const override; }; -inline void SvxBoxItem::SetAllDistances(sal_uInt16 const nNew) +inline void SvxBoxItem::SetAllDistances(sal_Int16 const nNew) { nTopDist = nBottomDist = nLeftDist = nRightDist = nNew; } @@ -240,7 +241,7 @@ namespace editeng { void EDITENG_DLLPUBLIC BorderDistanceFromWord(bool bFromEdge, sal_Int32& nMargin, - sal_Int32& nBorderDistance, sal_Int32 nBorderWidth); + sal_Int32& nBorderDistance, sal_Int32 nBorderWidth, bool bAllowNegativeBorderDistance = false); struct EDITENG_DLLPUBLIC WordPageMargins final { diff --git a/sw/ooxmlexport_setup.mk b/sw/ooxmlexport_setup.mk index 404ee5153438..f19e41f28469 100644 --- a/sw/ooxmlexport_setup.mk +++ b/sw/ooxmlexport_setup.mk @@ -50,6 +50,7 @@ $(eval $(call gb_CppunitTest_use_externals,sw_ooxmlexport$(1),\ $(eval $(call gb_CppunitTest_set_include,sw_ooxmlexport$(1),\ -I$(SRCDIR)/sw/inc \ -I$(SRCDIR)/sw/source/core/inc \ + -I$(SRCDIR)/sw/source/uibase/inc \ -I$(SRCDIR)/sw/qa/inc \ $$(INCLUDE) \ )) diff --git a/sw/qa/core/layout/layout.cxx b/sw/qa/core/layout/layout.cxx index 58e5562f3f5c..a6a949b5337b 100644 --- a/sw/qa/core/layout/layout.cxx +++ b/sw/qa/core/layout/layout.cxx @@ -743,6 +743,77 @@ CPPUNIT_TEST_FIXTURE(SwCoreLayoutTest, testDoublePageBorder) CPPUNIT_ASSERT_GREATER(aBorderWidthVec[2], aBorderWidthVec[3]); } +CPPUNIT_TEST_FIXTURE(SwCoreLayoutTest, testNegativePageBorder) +{ + // Given a document with a top margin and a negative border distance: + createSwDoc(); + SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get()); + SwDocShell* pDocShell = pTextDoc->GetDocShell(); + SwWrtShell* pWrtShell = pDocShell->GetWrtShell(); + pWrtShell->Insert("test"); + uno::Reference<beans::XPropertySet> xPageStyle(getStyles("PageStyles")->getByName("Standard"), + uno::UNO_QUERY); + xPageStyle->setPropertyValue("TopMargin", uno::Any(static_cast<sal_Int32>(501))); // 284 twips + table::BorderLine2 aBorder; + aBorder.LineWidth = 159; // 90 twips + aBorder.OuterLineWidth = 159; + xPageStyle->setPropertyValue("TopBorder", uno::Any(aBorder)); + sal_Int32 nTopBorderDistance = -646; // -366 twips + xPageStyle->setPropertyValue("TopBorderDistance", uno::Any(nTopBorderDistance)); + nTopBorderDistance = 0; + xPageStyle->getPropertyValue("TopBorderDistance") >>= nTopBorderDistance; + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(-646), nTopBorderDistance); + + // When rendering that border: + std::shared_ptr<GDIMetaFile> xMetaFile = pDocShell->GetPreviewMetaFile(); + + // Then make sure that the negative distance pushes the horizontal borderline down: + MetafileXmlDump aDumper; + xmlDocUniquePtr pXmlDoc = dumpAndParse(aDumper, *xMetaFile); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 899 + // - Actual : 524 + // i.e. the negative border distance was rounded up to 0 in lcl_CalcBorderRect(). + // Ideally this would be 284 (top of first page) + 284 (top margin) + 366 (border distance) = + // 934. + assertXPath(pXmlDoc, "//polyline[@style='solid']/point[1]", "y", "899"); + assertXPath(pXmlDoc, "//polyline[@style='solid']/point[2]", "y", "899"); +} + +CPPUNIT_TEST_FIXTURE(SwCoreLayoutTest, testNegativePageBorderNoMargin) +{ + // Given a document with no top margin and a negative border distance: + createSwDoc(); + SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get()); + SwDocShell* pDocShell = pTextDoc->GetDocShell(); + SwWrtShell* pWrtShell = pDocShell->GetWrtShell(); + pWrtShell->Insert("test"); + uno::Reference<beans::XPropertySet> xPageStyle(getStyles("PageStyles")->getByName("Standard"), + uno::UNO_QUERY); + xPageStyle->setPropertyValue("TopMargin", uno::Any(static_cast<sal_Int32>(0))); // 0 twips + table::BorderLine2 aBorder; + aBorder.LineWidth = 159; // 90 twips + aBorder.OuterLineWidth = 159; + xPageStyle->setPropertyValue("TopBorder", uno::Any(aBorder)); + sal_Int32 nTopBorderDistance = -1147; // -650 twips + xPageStyle->setPropertyValue("TopBorderDistance", uno::Any(nTopBorderDistance)); + + // When rendering that border: + std::shared_ptr<GDIMetaFile> xMetaFile = pDocShell->GetPreviewMetaFile(); + + // Then make sure that the negative distance pushes the horizontal borderline down: + MetafileXmlDump aDumper; + xmlDocUniquePtr pXmlDoc = dumpAndParse(aDumper, *xMetaFile); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 899 + // - Actual : 329 + // i.e. this failed differently: the lack of top margin caused a second problem. + // Ideally this would be 284 (top of first page) + 650 (border distance) = + // 934. + assertXPath(pXmlDoc, "//polyline[@style='solid']/point[1]", "y", "899"); + assertXPath(pXmlDoc, "//polyline[@style='solid']/point[2]", "y", "899"); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx index d85a8da12f18..bcd34ff459a2 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx @@ -7,6 +7,10 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include <swmodeltestbase.hxx> + +#include <queue> + #include <com/sun/star/beans/NamedValue.hpp> #include <com/sun/star/text/XBookmarksSupplier.hpp> #include <com/sun/star/text/XFootnotesSupplier.hpp> @@ -25,8 +29,9 @@ #include <o3tl/string_view.hxx> #include <comphelper/propertyvalue.hxx> -#include <queue> -#include <swmodeltestbase.hxx> +#include <unotxdoc.hxx> +#include <docsh.hxx> +#include <wrtsh.hxx> constexpr OUStringLiteral DATA_DIRECTORY = u"/sw/qa/extras/ooxmlexport/data/"; @@ -417,6 +422,39 @@ CPPUNIT_TEST_FIXTURE(Test, testDateContentControlExport) assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w15:color", "val", "008000"); } +CPPUNIT_TEST_FIXTURE(Test, testNegativePageBorder) +{ + // Given a document with a negative border distance: + createSwDoc(); + SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get()); + SwDocShell* pDocShell = pTextDoc->GetDocShell(); + SwWrtShell* pWrtShell = pDocShell->GetWrtShell(); + pWrtShell->Insert("test"); + uno::Reference<beans::XPropertySet> xPageStyle(getStyles("PageStyles")->getByName("Standard"), + uno::UNO_QUERY); + xPageStyle->setPropertyValue("TopMargin", uno::Any(static_cast<sal_Int32>(501))); + table::BorderLine2 aBorder; + aBorder.LineWidth = 159; + aBorder.OuterLineWidth = 159; + xPageStyle->setPropertyValue("TopBorder", uno::Any(aBorder)); + sal_Int32 nTopBorderDistance = -646; + xPageStyle->setPropertyValue("TopBorderDistance", uno::Any(nTopBorderDistance)); + + // When exporting to DOCX: + save("Office Open XML Text", maTempFile); + mbExported = true; + + // Then make sure that the page edge -> border space is correct: + xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml"); + assertXPath(pXmlDoc, "//w:pgMar", "top", "284"); + assertXPath(pXmlDoc, "//w:pgBorders/w:top", "sz", "36"); + // Without the fix in place, this test would have failed with: + // - Expected: 28 + // - Actual : 0 + // i.e. editeng::BorderDistancesToWord() mis-handled negative border distances. + assertXPath(pXmlDoc, "//w:pgBorders/w:top", "space", "28"); +} + CPPUNIT_TEST_FIXTURE(Test, testTdf148494) { loadAndSave("tdf148494.docx"); diff --git a/sw/qa/extras/ww8import/ww8import.cxx b/sw/qa/extras/ww8import/ww8import.cxx index 7eb0c9f6b221..ab35fa9d7346 100644 --- a/sw/qa/extras/ww8import/ww8import.cxx +++ b/sw/qa/extras/ww8import/ww8import.cxx @@ -182,7 +182,7 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf121734) for (auto eLine : { SvxBoxItemLine::TOP, SvxBoxItemLine::BOTTOM, SvxBoxItemLine::LEFT, SvxBoxItemLine::RIGHT }) { - CPPUNIT_ASSERT_EQUAL(sal_uInt16(0), pBox->GetDistance(eLine)); + CPPUNIT_ASSERT_EQUAL(sal_Int16(0), pBox->GetDistance(eLine)); CPPUNIT_ASSERT(!pBox->GetLine(eLine)); } } @@ -251,7 +251,7 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf122425_1) for (auto eLine : { SvxBoxItemLine::TOP, SvxBoxItemLine::BOTTOM, SvxBoxItemLine::LEFT, SvxBoxItemLine::RIGHT }) { - CPPUNIT_ASSERT_EQUAL(sal_uInt16(0), pBox->GetDistance(eLine)); + CPPUNIT_ASSERT_EQUAL(sal_Int16(0), pBox->GetDistance(eLine)); CPPUNIT_ASSERT(!pBox->GetLine(eLine)); } } diff --git a/sw/source/core/layout/paintfrm.cxx b/sw/source/core/layout/paintfrm.cxx index 560dd0f659bc..d470b1ae030f 100644 --- a/sw/source/core/layout/paintfrm.cxx +++ b/sw/source/core/layout/paintfrm.cxx @@ -1291,10 +1291,10 @@ static void lcl_CalcBorderRect( SwRect &rRect, const SwFrame *pFrame, const SvxBoxItem &rBox = rAttrs.GetBox(); const bool bTop = 0 != (pFrame->*fnRect->fnGetTopMargin)(); - if ( bTop ) + if ( bTop || rBox.GetTop() ) { SwTwips nDiff = rBox.GetTop() ? - rBox.CalcLineSpace( SvxBoxItemLine::TOP ) : + rBox.CalcLineSpace( SvxBoxItemLine::TOP, /*bEvenIfNoLine=*/false, /*bAllowNegative=*/true ) : rBox.GetDistance( SvxBoxItemLine::TOP ); if( nDiff ) (rRect.*fnRect->fnSubTop)( nDiff ); diff --git a/sw/source/filter/ww8/wrtww8.cxx b/sw/source/filter/ww8/wrtww8.cxx index faa25df0ec62..dafba458ec05 100644 --- a/sw/source/filter/ww8/wrtww8.cxx +++ b/sw/source/filter/ww8/wrtww8.cxx @@ -2594,7 +2594,7 @@ void WW8AttributeOutput::TableCellBorders( sal_uInt8 nSideBits[4] = {0, 0, 0, 0}; // 0001:top, 0010:left, 0100:bottom, 1000:right for ( int i = 0; i < 4; ++i ) // sides: top, left, bottom, right { - nMargin[i] = std::min(sal_uInt16(31680), pLastBox->GetDistance( aBorders[i] )); + nMargin[i] = std::min(sal_Int16(31680), pLastBox->GetDistance( aBorders[i] )); if ( nMargin[i] == nDefaultMargin[i] ) continue; diff --git a/sw/source/uibase/shells/tabsh.cxx b/sw/source/uibase/shells/tabsh.cxx index 9dbb1b689e8e..3cbea6b77389 100644 --- a/sw/source/uibase/shells/tabsh.cxx +++ b/sw/source/uibase/shells/tabsh.cxx @@ -512,7 +512,7 @@ void SwTableShell::Execute(SfxRequest &rReq) if ( pBoxItem ) { aBox.reset(pBoxItem->Clone()); - sal_uInt16 nDefValue = MIN_BORDER_DIST; + sal_Int16 nDefValue = MIN_BORDER_DIST; if ( !rReq.IsAPI() ) nDefValue = 55; if (!rReq.IsAPI() || aBox->GetSmallestDistance() < MIN_BORDER_DIST) diff --git a/writerfilter/qa/cppunittests/dmapper/PropertyMap.cxx b/writerfilter/qa/cppunittests/dmapper/PropertyMap.cxx index ae32ce1e4dc7..cc651d224736 100644 --- a/writerfilter/qa/cppunittests/dmapper/PropertyMap.cxx +++ b/writerfilter/qa/cppunittests/dmapper/PropertyMap.cxx @@ -16,6 +16,7 @@ #include <com/sun/star/style/XStyleFamiliesSupplier.hpp> #include <com/sun/star/beans/XPropertySet.hpp> #include <com/sun/star/drawing/XDrawPageSupplier.hpp> +#include <com/sun/star/table/BorderLine2.hpp> using namespace ::com::sun::star; @@ -108,6 +109,65 @@ CPPUNIT_TEST_FIXTURE(Test, testTableNegativeVerticalPos) // i.e. this was imported as a plain table, resulting in a 0 top margin (y pos too large). CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), xDrawPage->getCount()); } + +CPPUNIT_TEST_FIXTURE(Test, testNegativePageBorder) +{ + // Given a document with a top margin and a border which has more spacing than the margin: + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "negative-page-border.docx"; + + // When loading that document: + getComponent() = loadFromDesktop(aURL); + + // Then make sure that the border distance is negative, so it can appear at the correct + // position: + uno::Reference<style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(getComponent(), + uno::UNO_QUERY); + uno::Reference<container::XNameAccess> xStyleFamilies + = xStyleFamiliesSupplier->getStyleFamilies(); + uno::Reference<container::XNameAccess> xStyleFamily(xStyleFamilies->getByName("PageStyles"), + uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xStyle(xStyleFamily->getByName("Standard"), uno::UNO_QUERY); + auto nTopMargin = xStyle->getPropertyValue("TopMargin").get<sal_Int32>(); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(501), nTopMargin); + auto aTopBorder = xStyle->getPropertyValue("TopBorder").get<table::BorderLine2>(); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(159), aTopBorder.LineWidth); + auto nTopBorderDistance = xStyle->getPropertyValue("TopBorderDistance").get<sal_Int32>(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: -646 + // - Actual : 0 + // i.e. the border negative distance was lost. + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(-646), nTopBorderDistance); +} + +CPPUNIT_TEST_FIXTURE(Test, testNegativePageBorderNoMargin) +{ + // Given a document with no top margin and a border which has spacing: + OUString aURL + = m_directories.getURLFromSrc(DATA_DIRECTORY) + "negative-page-border-no-margin.docx"; + + // When loading that document: + getComponent() = loadFromDesktop(aURL); + + // Then make sure that the border distance is negative, so it can appear at the correct + // position: + uno::Reference<style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(getComponent(), + uno::UNO_QUERY); + uno::Reference<container::XNameAccess> xStyleFamilies + = xStyleFamiliesSupplier->getStyleFamilies(); + uno::Reference<container::XNameAccess> xStyleFamily(xStyleFamilies->getByName("PageStyles"), + uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xStyle(xStyleFamily->getByName("Standard"), uno::UNO_QUERY); + auto nTopMargin = xStyle->getPropertyValue("TopMargin").get<sal_Int32>(); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), nTopMargin); + auto aTopBorder = xStyle->getPropertyValue("TopBorder").get<table::BorderLine2>(); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(159), aTopBorder.LineWidth); + auto nTopBorderDistance = xStyle->getPropertyValue("TopBorderDistance").get<sal_Int32>(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: -1147 + // - Actual : 0 + // i.e. the border negative distance was lost. + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(-1147), nTopBorderDistance); +} } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerfilter/qa/cppunittests/dmapper/data/negative-page-border-no-margin.docx b/writerfilter/qa/cppunittests/dmapper/data/negative-page-border-no-margin.docx new file mode 100644 index 000000000000..8bd464a9ea6c Binary files /dev/null and b/writerfilter/qa/cppunittests/dmapper/data/negative-page-border-no-margin.docx differ diff --git a/writerfilter/qa/cppunittests/dmapper/data/negative-page-border.docx b/writerfilter/qa/cppunittests/dmapper/data/negative-page-border.docx new file mode 100644 index 000000000000..878ba1e7899b Binary files /dev/null and b/writerfilter/qa/cppunittests/dmapper/data/negative-page-border.docx differ diff --git a/writerfilter/source/dmapper/PropertyMap.cxx b/writerfilter/source/dmapper/PropertyMap.cxx index e1814a8ce1d5..645cc8c00c86 100644 --- a/writerfilter/source/dmapper/PropertyMap.cxx +++ b/writerfilter/source/dmapper/PropertyMap.cxx @@ -670,7 +670,7 @@ void SectionPropertyMap::SetBorderDistance( const uno::Reference< beans::XProper sal_Int32 nMargin = 0; aMargin >>= nMargin; editeng::BorderDistanceFromWord(eOffsetFrom == BorderOffsetFrom::Edge, nMargin, nDistance, - nLineWidth); + nLineWidth, /*bAllowNegativeBorderDistance=*/true); if (eOffsetFrom == BorderOffsetFrom::Edge) { commit f4b6cee77e1725837f9a6044fec0b561c7049c3b Author: Stephan Bergmann <sberg...@redhat.com> AuthorDate: Fri Jun 3 10:22:43 2022 +0200 Commit: Stephan Bergmann <sberg...@redhat.com> CommitDate: Tue Jun 7 08:45:31 2022 +0200 Use o3tl::make_unsigned, OString::getLength() is guaranteed to be non-negative Change-Id: Ibddd4f2b3d8680c94fd0ab45f6ed6204215c6009 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135339 Tested-by: Jenkins Reviewed-by: Stephan Bergmann <sberg...@redhat.com> diff --git a/desktop/source/deployment/dp_persmap.cxx b/desktop/source/deployment/dp_persmap.cxx index 652e5d2ea5ff..8b032fffb96e 100644 --- a/desktop/source/deployment/dp_persmap.cxx +++ b/desktop/source/deployment/dp_persmap.cxx @@ -23,6 +23,7 @@ #include <dp_misc.h> #include <dp_persmap.h> +#include <o3tl/safeint.hxx> #include <rtl/byteseq.hxx> #include <rtl/strbuf.hxx> #include <sal/log.hxx> @@ -243,13 +244,13 @@ void PersistentMap::flush() const OString aKeyString = encodeString( entry.first); const sal_Int32 nKeyLen = aKeyString.getLength(); m_MapFile.write( aKeyString.getStr(), nKeyLen, nBytesWritten); - OSL_ASSERT( nKeyLen == static_cast<sal_Int32>(nBytesWritten)); + OSL_ASSERT( o3tl::make_unsigned(nKeyLen) == nBytesWritten); m_MapFile.write( "\n", 1, nBytesWritten); // write line for value const OString& rValString = encodeString( entry.second); const sal_Int32 nValLen = rValString.getLength(); m_MapFile.write( rValString.getStr(), nValLen, nBytesWritten); - OSL_ASSERT( nValLen == static_cast<sal_Int32>(nBytesWritten)); + OSL_ASSERT( o3tl::make_unsigned(nValLen) == nBytesWritten); m_MapFile.write( "\n", 1, nBytesWritten); }