sw/qa/core/text/text.cxx | 52 +++++++++++++++++++++++++++++++++++++++++ sw/qa/unit/swmodeltestbase.cxx | 6 ++-- sw/source/core/inc/txtfly.hxx | 11 ++------ sw/source/core/text/porrst.cxx | 2 - sw/source/core/text/txtfly.cxx | 37 +++++++++++++++++++++++------ 5 files changed, 89 insertions(+), 19 deletions(-)
New commits: commit e799ebfd7a2deab13b47092807335670abb7b485 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Mon Mar 28 08:45:53 2022 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Mon Mar 28 10:22:51 2022 +0200 sw clearing breaks: add layout support for the left and right cases This means that the vertical position calculated in SwTextFly now depend son the horizontal position of the break portion, so it doesn't make sense to cache it. Change-Id: I4e30bb12d9ba117d3af065881a65a1c2001e1164 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132162 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins diff --git a/sw/qa/core/text/text.cxx b/sw/qa/core/text/text.cxx index 317139c5ec37..0d5d6f94b3bc 100644 --- a/sw/qa/core/text/text.cxx +++ b/sw/qa/core/text/text.cxx @@ -320,6 +320,58 @@ CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testClearingLineBreakAtStart) assertXPath(pXmlDoc, "//SwParaPortion/SwLineLayout[1]", "height", "1024"); } +CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testClearingLineBreakLeft) +{ + // Given a document with two anchored objects (left height is 5cm, right height is 7.5cm) and a + // clearing break (type=left): + loadURL("private:factory/swriter", nullptr); + uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY); + uno::Reference<text::XTextDocument> xDocument(mxComponent, uno::UNO_QUERY); + uno::Reference<text::XText> xText = xDocument->getText(); + uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor(); + { + uno::Reference<drawing::XShape> xShape( + xFactory->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY); + xShape->setSize(awt::Size(5000, 5000)); + uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY); + xShapeProps->setPropertyValue("AnchorType", + uno::makeAny(text::TextContentAnchorType_AT_CHARACTER)); + uno::Reference<text::XTextContent> xShapeContent(xShape, uno::UNO_QUERY); + xText->insertTextContent(xCursor, xShapeContent, /*bAbsorb=*/false); + } + { + uno::Reference<drawing::XShape> xShape( + xFactory->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY); + xShape->setSize(awt::Size(5000, 7500)); + uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY); + xShapeProps->setPropertyValue("AnchorType", + uno::makeAny(text::TextContentAnchorType_AT_CHARACTER)); + xShapeProps->setPropertyValue("HoriOrientPosition", uno::makeAny(sal_Int32(10000))); + uno::Reference<text::XTextContent> xShapeContent2(xShape, uno::UNO_QUERY); + xText->insertTextContent(xCursor, xShapeContent2, /*bAbsorb=*/false); + } + uno::Reference<text::XTextContent> xLineBreak( + xFactory->createInstance("com.sun.star.text.LineBreak"), uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xLineBreakProps(xLineBreak, uno::UNO_QUERY); + auto eClear = static_cast<sal_Int16>(SwLineBreakClear::LEFT); + xLineBreakProps->setPropertyValue("Clear", uno::makeAny(eClear)); + xText->insertString(xCursor, "foo", /*bAbsorb=*/false); + xText->insertTextContent(xCursor, xLineBreak, /*bAbsorb=*/false); + xText->insertString(xCursor, "bar", /*bAbsorb=*/false); + + // When laying out that document: + calcLayout(); + + // Then make sure the "bar" jumps down below the left shape, but not below the right shape (due + // to type=left): + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 2837 + // - Actual : 4254 + // i.e. any non-none type was handled as type=all, and this was jumping below both shapes. + assertXPath(pXmlDoc, "//SwParaPortion/SwLineLayout[1]", "height", "2837"); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/qa/unit/swmodeltestbase.cxx b/sw/qa/unit/swmodeltestbase.cxx index ad4ff03d5479..284e42e17587 100644 --- a/sw/qa/unit/swmodeltestbase.cxx +++ b/sw/qa/unit/swmodeltestbase.cxx @@ -220,9 +220,9 @@ xmlDocUniquePtr SwModelTestBase::parseLayoutDump() if (!mpXmlBuffer) dumpLayout(mxComponent); - return xmlDocUniquePtr( - xmlParseMemory(reinterpret_cast<const char*>(xmlBufferContent(mpXmlBuffer)), - xmlBufferLength(mpXmlBuffer))); + auto pBuffer = reinterpret_cast<const char*>(xmlBufferContent(mpXmlBuffer)); + SAL_INFO("sw", "SwModelTestBase::parseLayoutDump: pBuffer is '" << pBuffer << "'"); + return xmlDocUniquePtr(xmlParseMemory(pBuffer, xmlBufferLength(mpXmlBuffer))); } OUString SwModelTestBase::parseDump(const OString& aXPath, const OString& aAttribute) diff --git a/sw/source/core/inc/txtfly.hxx b/sw/source/core/inc/txtfly.hxx index 39f11a835421..37d78e3c822f 100644 --- a/sw/source/core/inc/txtfly.hxx +++ b/sw/source/core/inc/txtfly.hxx @@ -35,6 +35,8 @@ class SwAnchoredObject; class SwTextFrame; class SwDrawTextInfo; class SwContourCache; +class SwBreakPortion; +class SwTextFormatInfo; typedef std::vector< SwAnchoredObject* > SwAnchoredObjList; @@ -125,7 +127,6 @@ class SwTextFly std::unique_ptr<SwAnchoredObjList> mpAnchoredObjList; tools::Long m_nMinBottom; - mutable tools::Long m_nMaxBottom; tools::Long m_nNextTop; /// Stores the upper edge of the "next" frame SwNodeOffset m_nCurrFrameNodeIndex; @@ -201,7 +202,6 @@ class SwTextFly const bool bInFooterOrHeader ); SwTwips CalcMinBottom() const; - SwTwips CalcMaxBottom() const; const SwTextFrame* GetMaster_(); @@ -231,7 +231,7 @@ public: SwTwips GetMinBottom() const; /// Gets the maximum of the fly frame bottoms. - SwTwips GetMaxBottom() const; + SwTwips GetMaxBottom(const SwBreakPortion& rPortion, const SwTextFormatInfo& rInfo) const; const SwTextFrame* GetMaster() const; @@ -344,11 +344,6 @@ inline SwTwips SwTextFly::GetMinBottom() const return mpAnchoredObjList ? m_nMinBottom : CalcMinBottom(); } -inline SwTwips SwTextFly::GetMaxBottom() const -{ - return mpAnchoredObjList ? m_nMaxBottom : CalcMaxBottom(); -} - inline const SwTextFrame* SwTextFly::GetMaster() const { return m_pMaster ? m_pMaster : const_cast<SwTextFly*>(this)->GetMaster_(); diff --git a/sw/source/core/text/porrst.cxx b/sw/source/core/text/porrst.cxx index 82467d110aa6..b5e98e913f14 100644 --- a/sw/source/core/text/porrst.cxx +++ b/sw/source/core/text/porrst.cxx @@ -182,7 +182,7 @@ bool SwBreakPortion::Format( SwTextFormatInfo &rInf ) SwTextFly& rTextFly = rInf.GetTextFly(); if (rTextFly.IsOn()) { - SwTwips nHeight = rTextFly.GetMaxBottom() - rInf.Y(); + SwTwips nHeight = rTextFly.GetMaxBottom(*this, rInf) - rInf.Y(); if (nHeight > Height()) { Height(nHeight, /*bText=*/false); diff --git a/sw/source/core/text/txtfly.cxx b/sw/source/core/text/txtfly.cxx index aa193c50220f..1b9c3b55308a 100644 --- a/sw/source/core/text/txtfly.cxx +++ b/sw/source/core/text/txtfly.cxx @@ -33,6 +33,8 @@ #include <frmtool.hxx> #include <ndtxt.hxx> #include <txtfly.hxx> +#include "inftxt.hxx" +#include "porrst.hxx" #include "txtpaint.hxx" #include <notxtfrm.hxx> #include <fmtcnct.hxx> @@ -48,6 +50,7 @@ #include <sortedobjs.hxx> #include <IDocumentDrawModelAccess.hxx> #include <IDocumentSettingAccess.hxx> +#include <formatlinebreak.hxx> #include <svx/svdoedge.hxx> #ifdef DBG_UTIL @@ -309,7 +312,6 @@ SwTextFly::SwTextFly() , m_pCurrFrame(nullptr) , m_pMaster(nullptr) , m_nMinBottom(0) - , m_nMaxBottom(0) , m_nNextTop(0) , m_nCurrFrameNodeIndex(0) , m_bOn(false) @@ -340,7 +342,6 @@ SwTextFly::SwTextFly( const SwTextFly& rTextFly ) m_bOn = rTextFly.m_bOn; m_bTopRule = rTextFly.m_bTopRule; m_nMinBottom = rTextFly.m_nMinBottom; - m_nMaxBottom = rTextFly.m_nMaxBottom; m_nNextTop = rTextFly.m_nNextTop; m_nCurrFrameNodeIndex = rTextFly.m_nCurrFrameNodeIndex; mbIgnoreCurrentFrame = rTextFly.mbIgnoreCurrentFrame; @@ -371,7 +372,6 @@ void SwTextFly::CtorInitTextFly( const SwTextFrame *pFrame ) m_bOn = m_pPage->GetSortedObjs() != nullptr; m_bTopRule = true; m_nMinBottom = 0; - m_nMaxBottom = 0; m_nNextTop = 0; m_nCurrFrameNodeIndex = NODE_OFFSET_MAX; } @@ -958,8 +958,6 @@ SwAnchoredObjList* SwTextFly::InitAnchoredObjList() mpAnchoredObjList.reset( new SwAnchoredObjList ); } - CalcMaxBottom(); - // #i68520# return mpAnchoredObjList.get(); } @@ -998,22 +996,47 @@ SwTwips SwTextFly::CalcMinBottom() const return nRet; } -SwTwips SwTextFly::CalcMaxBottom() const +SwTwips SwTextFly::GetMaxBottom(const SwBreakPortion& rPortion, const SwTextFormatInfo& rInfo) const { SwTwips nRet = 0; size_t nCount(m_bOn ? GetAnchoredObjList()->size() : 0); SwRectFnSet aRectFnSet(m_pCurrFrame); + + // Get the horizontal position of the break portion in absolute twips. The frame area is in + // absolute twips, the frame's print area is relative to the frame area. Finally the portion's + // position is relative to the frame's print area. + SwTwips nX = rInfo.X(); + nX += aRectFnSet.GetLeft(m_pCurrFrame->getFrameArea()); + nX += aRectFnSet.GetLeft(m_pCurrFrame->getFramePrintArea()); + for (size_t i = 0; i < nCount; ++i) { const SwAnchoredObject* pAnchoredObj = (*mpAnchoredObjList)[i]; SwRect aRect(pAnchoredObj->GetObjRectWithSpaces()); + if (rPortion.GetClear() == SwLineBreakClear::LEFT) + { + if (nX < aRectFnSet.GetLeft(aRect)) + { + // Want to jump down to the first line that's unblocked on the left. This object is + // on the right of the break, ignore it. + continue; + } + } + if (rPortion.GetClear() == SwLineBreakClear::RIGHT) + { + if (nX > aRectFnSet.GetRight(aRect)) + { + // Want to jump down to the first line that's unblocked on the right. This object is + // on the left of the break, ignore it. + continue; + } + } SwTwips nBottom = aRectFnSet.GetBottom(aRect); if (nBottom > nRet) { nRet = nBottom; } } - m_nMaxBottom = nRet; return nRet; }