summaryrefslogtreecommitdiff
path: root/sw
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2019-09-19 16:41:06 +0200
committerMiklos Vajna <vmiklos@collabora.com>2019-09-19 18:30:57 +0200
commitd37096f59e7e0286e55008153591a60bab92b9e8 (patch)
tree6c7760fbe0c0c44d8b6ffe29ac875a13c4104938 /sw
parent428b67cd0d490739f9a7bb5a724020179ba7591d (diff)
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 <vmiklos@collabora.com> Tested-by: Jenkins
Diffstat (limited to 'sw')
-rw-r--r--sw/qa/extras/layout/layout.cxx58
-rw-r--r--sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx30
2 files changed, 88 insertions, 0 deletions
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<lang::XMultiServiceFactory> xDocument(mxComponent, uno::UNO_QUERY);
+ awt::Point aPoint(1000, 1000);
+ awt::Size aSize(2000, 2000);
+ uno::Reference<drawing::XShape> xShape(
+ xDocument->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY);
+ xShape->setPosition(aPoint);
+ xShape->setSize(aSize);
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(xDocument, uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> 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<SwXTextDocument*>(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<size_t>(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
+ // <bounds left="1984" top="1984" width="1137" height="1137"/>
+ // <bounds left="2551" top="2551" width="1137" height="1137"/>
+ // 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 <frmtool.hxx>
#include <ndtxt.hxx>
#include <dflyobj.hxx>
+#include <fmtwrapinfluenceonobjpos.hxx>
+#include <sortedobjs.hxx>
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