From d37096f59e7e0286e55008153591a60bab92b9e8 Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Thu, 19 Sep 2019 16:41:06 +0200 Subject: Related: tdf#124600 sw anchored object allow overlap: add layout If there is an overlap, then a shift towards the bottom or towards the right would resolve that. Word seems to always push down, do the same for compatibility. Otherwise, let's see if some fine-tuning will be needed for the behavior, sadly "20.4.2.3 anchor (Anchor for Floating DrawingML Object)" in the OOXML spec (the allowOverlap part) only says the overlapping object has to be re-positioned, but does no go into details. Change-Id: Ie1b4626f6d06862d617e28e0cb74838107d993d1 Reviewed-on: https://gerrit.libreoffice.org/79141 Reviewed-by: Miklos Vajna Tested-by: Jenkins --- sw/qa/extras/layout/layout.cxx | 58 ++++++++++++++++++++++ .../tocntntanchoredobjectposition.cxx | 30 +++++++++++ 2 files changed, 88 insertions(+) (limited to 'sw') diff --git a/sw/qa/extras/layout/layout.cxx b/sw/qa/extras/layout/layout.cxx index 59e1e08939e0..2110eed1e31c 100644 --- a/sw/qa/extras/layout/layout.cxx +++ b/sw/qa/extras/layout/layout.cxx @@ -3096,6 +3096,64 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf127235) pDoc->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout(); } +CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testShapeAllowOverlap) +{ +// Need to find out why this fails on macOS. +#ifndef MACOSX + // Create an empty document with two, intentionally overlapping shapes. + // Set their AllowOverlap property to false. + loadURL("private:factory/swriter", nullptr); + uno::Reference xDocument(mxComponent, uno::UNO_QUERY); + awt::Point aPoint(1000, 1000); + awt::Size aSize(2000, 2000); + uno::Reference xShape( + xDocument->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY); + xShape->setPosition(aPoint); + xShape->setSize(aSize); + uno::Reference xDrawPageSupplier(xDocument, uno::UNO_QUERY); + uno::Reference xShapeProperties(xShape, uno::UNO_QUERY); + xShapeProperties->setPropertyValue("AllowOverlap", uno::makeAny(false)); + xShapeProperties->setPropertyValue("AnchorType", + uno::makeAny(text::TextContentAnchorType_AT_CHARACTER)); + xDrawPageSupplier->getDrawPage()->add(xShape); + + aPoint = awt::Point(2000, 2000); + xShape.set(xDocument->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY); + xShape->setPosition(aPoint); + xShape->setSize(aSize); + xShapeProperties.set(xShape, uno::UNO_QUERY); + xShapeProperties->setPropertyValue("AllowOverlap", uno::makeAny(false)); + xShapeProperties->setPropertyValue("AnchorType", + uno::makeAny(text::TextContentAnchorType_AT_CHARACTER)); + xDrawPageSupplier->getDrawPage()->add(xShape); + + // Now verify that the rectangle of the anchored objects don't overlap. + SwXTextDocument* pTextDoc = dynamic_cast(mxComponent.get()); + CPPUNIT_ASSERT(pTextDoc); + SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc(); + SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout(); + SwFrame* pPageFrame = pLayout->GetLower(); + SwFrame* pBodyFrame = pPageFrame->GetLower(); + SwFrame* pTextFrame = pBodyFrame->GetLower(); + CPPUNIT_ASSERT(pTextFrame->GetDrawObjs()); + SwSortedObjs& rObjs = *pTextFrame->GetDrawObjs(); + CPPUNIT_ASSERT_EQUAL(static_cast(2), rObjs.size()); + SwAnchoredObject* pFirst = rObjs[0]; + SwAnchoredObject* pSecond = rObjs[1]; + // Without the accompanying fix in place, this test would have failed: the layout dump was + // + // + // so there was a clear vertical overlap. (Allow for 1px tolerance.) + OString aMessage("Unexpected overlap: first shape's bottom is "); + aMessage += OString::number(pFirst->GetObjRect().Bottom()); + aMessage += ", second shape's top is "; + aMessage += OString::number(pSecond->GetObjRect().Top()); + CPPUNIT_ASSERT_MESSAGE(aMessage.getStr(), + std::abs(pFirst->GetObjRect().Bottom() - pSecond->GetObjRect().Top()) + < 15); +#endif +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx b/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx index 25424dfaa3f3..f26b48ac0a98 100644 --- a/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx +++ b/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx @@ -42,6 +42,8 @@ #include #include #include +#include +#include using namespace objectpositioning; using namespace ::com::sun::star; @@ -971,6 +973,34 @@ void SwToContentAnchoredObjectPosition::CalcPosition() // keep layout frame vertical position is oriented at. mpVertPosOrientFrame = pUpperOfOrientFrame; + // If it was requested to not overlap with already formatted objects, take care of that + // here. + bool bAllowOverlap = rFrameFormat.GetWrapInfluenceOnObjPos().GetAllowOverlap(); + if (!bAllowOverlap) + { + // Get the list of objects. + const SwSortedObjs& rSortedObjs = *pAnchorFrameForVertPos->GetDrawObjs(); + for (const auto& pAnchoredObj : rSortedObjs) + { + if (pAnchoredObj == &GetAnchoredObj()) + { + // We found ourselves, stop iterating. + break; + } + + if (!GetAnchoredObj().GetObjRect().IsOver(pAnchoredObj->GetObjRect())) + { + // Found an already positioned object, but it doesn't overlap, ignore. + continue; + } + + // Already formatted, overlaps: resolve the conflict by shifting ourselves down. + SwTwips nYDiff + = pAnchoredObj->GetObjRect().Bottom() - GetAnchoredObj().GetObjRect().Top(); + aRelPos.setY(aRelPos.getY() + nYDiff + 1); + GetAnchoredObj().SetObjTop(nTopOfAnch + aRelPos.Y()); + } + } } // determine 'horizontal' position -- cgit