tdf#135198 sw editing: text box fell out of its shape
Without this patch if a shape anchored to a paragraph and containing
a text box was moved upwards beyond the vertical position of its anchor,
the text box failed to keep its position in sync with the shape.
This is fixed by telling the text box the absolute vertical position of
the corresponding shape after the latter is moved.
Note: Other fix is associated to the shortcut keys
Shift-Arrow Up/Shift-Arrow Down for moving text frames with
bigger steps vertically. Now it's not possible to use these
keys, but that was bad with text boxes, because it moved only
the text content of the text box.
Note: this patch fixes the vertical position of the text box
of textbox-wps-only.docx of the unit test textboxWpsOnly.
Change-Id: Ib66b13cae455462c616fed6bbd088433c83e61a0
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/104520
Tested-by: László Németh <nemeth@numbertext.org>
Reviewed-by: László Németh <nemeth@numbertext.org>
diff --git a/sw/qa/core/layout/data/shape-textbox.odt b/sw/qa/core/layout/data/shape-textbox.odt
new file mode 100644
index 0000000..26a9eb7
--- /dev/null
+++ b/sw/qa/core/layout/data/shape-textbox.odt
Binary files differ
diff --git a/sw/qa/core/layout/layout.cxx b/sw/qa/core/layout/layout.cxx
index 8decbdf..7c6ae7df 100644
--- a/sw/qa/core/layout/layout.cxx
+++ b/sw/qa/core/layout/layout.cxx
@@ -14,6 +14,11 @@
#include <wrtsh.hxx>
#include <docsh.hxx>
#include <unotxdoc.hxx>
#include <flyfrm.hxx>
#include <fmtornt.hxx>
//#include <frameformats.hxx>
#include <frmtool.hxx>
#include <textboxhelper.hxx>
char const DATA_DIRECTORY[] = "/sw/qa/core/layout/data/";
@@ -163,6 +168,32 @@
assertXPath(pXmlDoc, "(//SwAnchoredDrawObject)[3]/bounds", "bottom", "3844");
}
CPPUNIT_TEST_FIXTURE(SwCoreLayoutTest, testTextBoxStaysInsideShape)
{
// tdf#135198: check whether text box stays inside shape after moving it upwards
load(DATA_DIRECTORY, "shape-textbox.odt");
SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
SwDocShell* pDocShell = pTextDoc->GetDocShell();
SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
SdrObject* pTextBoxObj = pWrtShell->GetObjAt({ 8000, 3000 });
xmlDocUniquePtr pLayoutBefore = parseLayoutDump();
CPPUNIT_ASSERT(pLayoutBefore);
const int nTextBoxTopBefore = getXPath(pLayoutBefore, "//fly/infos/bounds", "top").toInt32();
uno::Reference<drawing::XShape> xShape(pTextBoxObj->getUnoShape(), uno::UNO_QUERY_THROW);
auto aPosition = xShape->getPosition();
aPosition.Y -= 500;
xShape->setPosition(aPosition);
discardDumpedLayout();
xmlDocUniquePtr pLayoutAfter = parseLayoutDump();
CPPUNIT_ASSERT(pLayoutAfter);
const int nTextBoxTopAfter = getXPath(pLayoutAfter, "//fly/infos/bounds", "top").toInt32();
CPPUNIT_ASSERT_MESSAGE("text box was supposed to stay inside its shape",
nTextBoxTopAfter < nTextBoxTopBefore);
}
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx
index 5b22f0e..dbfd1fa 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx
@@ -661,9 +661,11 @@
// This was 10954.
CPPUNIT_ASSERT_EQUAL(sal_Int32(6008), getProperty<sal_Int32>(xEmbeddedObjects->getByIndex(0), "Width"));
// The following assert no longer applies due to tdf#135198
// Layout modified the document when it had this chart.
uno::Reference<util::XModifiable> xModifiable(mxComponent, uno::UNO_QUERY);
CPPUNIT_ASSERT_EQUAL(false, bool(xModifiable->isModified()));
//uno::Reference<util::XModifiable> xModifiable(mxComponent, uno::UNO_QUERY);
//CPPUNIT_ASSERT_EQUAL(false, bool(xModifiable->isModified()));
}
DECLARE_OOXMLEXPORT_TEST(testInlineGroupshape, "inline-groupshape.docx")
diff --git a/sw/qa/extras/ooxmlimport/ooxmlimport.cxx b/sw/qa/extras/ooxmlimport/ooxmlimport.cxx
index ee1b545..91029da 100644
--- a/sw/qa/extras/ooxmlimport/ooxmlimport.cxx
+++ b/sw/qa/extras/ooxmlimport/ooxmlimport.cxx
@@ -1065,7 +1065,8 @@
if ( nsScreen.frame.size.width * scaleFactor > 4000 )
return;
#endif
CPPUNIT_ASSERT_EQUAL(sal_Int32(2805), getProperty<sal_Int32>(xFrame, "VertOrientPosition"));
// Vertically oriented to page due to tdf#135198
CPPUNIT_ASSERT_EQUAL(sal_Int32(5304), getProperty<sal_Int32>(xFrame, "VertOrientPosition"));
}
DECLARE_OOXMLIMPORT_TEST(testGroupshapeRelsize, "groupshape-relsize.docx")
diff --git a/sw/source/core/layout/objectformattertxtfrm.cxx b/sw/source/core/layout/objectformattertxtfrm.cxx
index 18b882b..78498b9 100644
--- a/sw/source/core/layout/objectformattertxtfrm.cxx
+++ b/sw/source/core/layout/objectformattertxtfrm.cxx
@@ -30,6 +30,10 @@
#include <fmtfollowtextflow.hxx>
#include <layact.hxx>
#include <ftnfrm.hxx>
#include <fmtornt.hxx>
#include <textboxhelper.hxx>
#include <svx/svdobj.hxx>
#include <svx/svdpage.hxx>
using namespace ::com::sun::star;
@@ -340,6 +344,32 @@
( !mrAnchorTextFrame.IsFollow() &&
AtLeastOneObjIsTmpConsiderWrapInfluence() ) ) )
{
// tdf#135198: force text box to stay inside shape after layout changes
if (SwSortedObjs* pDrawObjs = mrAnchorTextFrame.GetDrawObjs())
{
// N.B.: avoid using ranged for because the iterator might get invalidated
for (size_t i = 0; i < pDrawObjs->size(); ++i)
{
SwAnchoredObject* const pObj = (*pDrawObjs)[i];
SwFrameFormat& rFormat = pObj->GetFrameFormat();
if (SwTextBoxHelper::isTextBox(&rFormat, RES_DRAWFRMFMT))
{
SfxItemSet aSet(rFormat.GetDoc()->GetAttrPool(),
svl::Items<RES_VERT_ORIENT, RES_ANCHOR>{});
if (const SwPageFrame* pPageFrame = pObj->GetPageFrame())
{
const SwRect& rPageFrameArea = pPageFrame->getFrameArea();
aSet.Put(SwFormatVertOrient(pObj->GetObjRect().Top() - rPageFrameArea.Top(),
text::VertOrientation::NONE,
text::RelOrientation::PAGE_FRAME));
aSet.Put(SwFormatAnchor(RndStdIds::FLY_AT_PAGE, pObj->GetPageFrame()->GetPhyPageNum()));
SwTextBoxHelper::syncFlyFrameAttr(rFormat, aSet);
}
}
}
}
const bool bDoesAnchorHadPrev = ( mrAnchorTextFrame.GetIndPrev() != nullptr );
// Format anchor text frame after its objects are formatted.