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;
 }
 

Reply via email to