sw/qa/core/text/text.cxx       |   52 +++++++++++++++++++++++++++++++++++++++++
 sw/qa/unit/swmodeltestbase.cxx |    6 ++--
 sw/source/core/inc/txtfly.hxx  |   11 ++------
 sw/source/core/text/inftxt.cxx |   27 ++++++++++++++++++++-
 sw/source/core/text/porrst.cxx |    2 -
 sw/source/core/text/txtfly.cxx |   37 +++++++++++++++++++++++------
 6 files changed, 115 insertions(+), 20 deletions(-)

New commits:
commit 6c6d9a5457af20f14a0e6344efa19b93e0f7c026
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Mon Mar 28 08:45:53 2022 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Thu Mar 31 13:10:25 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.
    
    (cherry picked from commit e799ebfd7a2deab13b47092807335670abb7b485)
    
    Change-Id: I4e30bb12d9ba117d3af065881a65a1c2001e1164
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132353
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/sw/qa/core/text/text.cxx b/sw/qa/core/text/text.cxx
index 9987fac58a3f..0923758694b8 100644
--- a/sw/qa/core/text/text.cxx
+++ b/sw/qa/core/text/text.cxx
@@ -293,6 +293,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 ee35a1cc7259..28ee075120fa 100644
--- a/sw/qa/unit/swmodeltestbase.cxx
+++ b/sw/qa/unit/swmodeltestbase.cxx
@@ -218,9 +218,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 82ee5f085d6a..f5d913f7df9d 100644
--- a/sw/source/core/inc/txtfly.hxx
+++ b/sw/source/core/inc/txtfly.hxx
@@ -36,6 +36,8 @@ class SwAnchoredObject;
 class SwTextFrame;
 class SwDrawTextInfo;
 class SwContourCache;
+class SwBreakPortion;
+class SwTextFormatInfo;
 
 typedef std::vector< SwAnchoredObject* > SwAnchoredObjList;
 
@@ -126,7 +128,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;
 
@@ -202,7 +203,6 @@ class SwTextFly
                  const bool bInFooterOrHeader );
 
     SwTwips CalcMinBottom() const;
-    SwTwips CalcMaxBottom() const;
 
     const SwTextFrame* GetMaster_();
 
@@ -232,7 +232,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;
 
@@ -345,11 +345,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;
 }
 
commit 3704aa48d00f96864679c3bdbcbf3f6dbeaf4e4c
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Fri Mar 25 08:37:22 2022 +0100
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Thu Mar 31 13:10:11 2022 +0200

    sw clearing breaks: add clearing indicator during rendering
    
    A left / right line around the break portion now allows seeing if the
    clearing is none, left, right or all (somewhat familiar from Word).
    
    No test for this, SwBreakPortion::Paint() is a NOP unless rendering on a
    window, so the metafile-based rendering used for testing won't detect
    the difference.
    
    (cherry picked from commit eb53efed80302c4ca6409c6dbd023d8ba1eb8e47)
    
    Change-Id: I3ff0c89bc4bb45deb03bea43c3ee4589887dee7c
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132352
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/sw/source/core/text/inftxt.cxx b/sw/source/core/text/inftxt.cxx
index 16af09c8ccbf..422187624cd9 100644
--- a/sw/source/core/text/inftxt.cxx
+++ b/sw/source/core/text/inftxt.cxx
@@ -67,6 +67,7 @@
 #include <vcl/virdev.hxx>
 #include <vcl/gradient.hxx>
 #include <i18nlangtag/mslangid.hxx>
+#include <formatlinebreak.hxx>
 
 using namespace ::com::sun::star;
 using namespace ::com::sun::star::linguistic2;
@@ -964,6 +965,13 @@ void SwTextPaintInfo::DrawLineBreak( const SwLinePortion 
&rPor ) const
     if( !OnWin() )
         return;
 
+    SwLineBreakClear eClear = SwLineBreakClear::NONE;
+    if (rPor.IsBreakPortion())
+    {
+        const auto& rBreakPortion = static_cast<const SwBreakPortion&>(rPor);
+        eClear = rBreakPortion.GetClear();
+    }
+
     sal_uInt16 nOldWidth = rPor.Width();
     const_cast<SwLinePortion&>(rPor).Width( LINE_BREAK_WIDTH );
 
@@ -976,7 +984,24 @@ void SwTextPaintInfo::DrawLineBreak( const SwLinePortion 
&rPor ) const
                                   CHAR_LINEBREAK_RTL : CHAR_LINEBREAK;
         const sal_uInt8 nOptions = 0;
 
-        lcl_DrawSpecial( *this, rPor, aRect, NON_PRINTING_CHARACTER_COLOR, 
cChar, nOptions );
+        SwRect aTextRect(aRect);
+        if (eClear == SwLineBreakClear::LEFT || eClear == 
SwLineBreakClear::ALL)
+            aTextRect.AddLeft(30);
+        if (eClear == SwLineBreakClear::RIGHT || eClear == 
SwLineBreakClear::ALL)
+            aTextRect.AddRight(-30);
+        lcl_DrawSpecial( *this, rPor, aTextRect, NON_PRINTING_CHARACTER_COLOR, 
cChar, nOptions );
+
+        if (eClear != SwLineBreakClear::NONE)
+        {
+            // Paint indicator if this clear is left/right/all.
+            m_pOut->Push(vcl::PushFlags::LINECOLOR);
+            m_pOut->SetLineColor(NON_PRINTING_CHARACTER_COLOR);
+            if (eClear != SwLineBreakClear::RIGHT)
+                m_pOut->DrawLine(aRect.BottomLeft(), aRect.TopLeft());
+            if (eClear != SwLineBreakClear::LEFT)
+                m_pOut->DrawLine(aRect.BottomRight(), aRect.TopRight());
+            m_pOut->Pop();
+        }
     }
 
     const_cast<SwLinePortion&>(rPor).Width( nOldWidth );

Reply via email to