sw/inc/viewsh.hxx                  |    2 
 sw/source/core/inc/hffrm.hxx       |    6 +
 sw/source/core/inc/pagefrm.hxx     |    3 
 sw/source/core/layout/paintfrm.cxx |  156 +++++++++++++++++++++++++++----------
 sw/source/core/view/viewsh.cxx     |   18 +++-
 5 files changed, 144 insertions(+), 41 deletions(-)

New commits:
commit ba0c39064fd97816774f4c06ca84c92c4a137450
Author:     Caolán McNamara <caolan.mcnam...@collabora.com>
AuthorDate: Wed Jul 26 16:31:04 2023 +0100
Commit:     Caolán McNamara <caolan.mcnam...@collabora.com>
CommitDate: Thu Jul 27 09:37:08 2023 +0200

    Invalidate less on entering/leaving header/footer
    
    Instead of invalidating the entire window, just invalidate the
    parts that need to change.
    
    Invalidate a sequence of Rectangles rather than bundle them
    into a vcl::Region. Currently Window::Invalidate(const vcl::Region&...
    does a LogicInvalidate(rRegion.GetBoundRect()) so get a mega rectangle
    that covers everthing which is the opposite of what I want to get here.
    It might be worth using GetRegionRectangles there.
    
    Change-Id: Idc3f5f7d19dd57da725072ec4161d932c0c26902
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/154973
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>

diff --git a/sw/inc/viewsh.hxx b/sw/inc/viewsh.hxx
index 8976452a0dc4..66eec0f5060e 100644
--- a/sw/inc/viewsh.hxx
+++ b/sw/inc/viewsh.hxx
@@ -188,6 +188,8 @@ class SW_DLLPUBLIC SwViewShell : public 
sw::Ring<SwViewShell>
 
     SAL_DLLPRIVATE void InvalidateAll(std::vector<LockPaintReason>& rReasons);
 
+    SAL_DLLPRIVATE void InvalidatePageAndHFSubsidiaryLines();
+
 protected:
     static ShellResource*      spShellRes;      ///< Resources for the Shell.
     static vcl::DeleteOnDeinit< std::shared_ptr<weld::Window> > spCareDialog;  
  ///< Avoid this window.
diff --git a/sw/source/core/inc/hffrm.hxx b/sw/source/core/inc/hffrm.hxx
index 32af4dab9e30..4fed2517db1e 100644
--- a/sw/source/core/inc/hffrm.hxx
+++ b/sw/source/core/inc/hffrm.hxx
@@ -22,8 +22,13 @@
 
 #include "layfrm.hxx"
 
+class SwViewShell;
+
 class SwHeadFootFrame : public SwLayoutFrame
 {
+private:
+    std::vector<basegfx::B2DPolygon> GetSubsidiaryLinesPolygons(const 
SwViewShell& rViewShell) const;
+
 protected:
     void FormatSize(SwTwips nUL, const SwBorderAttrs * pAttrs);
     void FormatPrt(SwTwips & nUL, const SwBorderAttrs * pAttrs);
@@ -37,6 +42,7 @@ public:
     virtual SwTwips ShrinkFrame( SwTwips,
                                bool bTst = false, bool bInfo = false ) 
override;
     virtual void PaintSubsidiaryLines( const SwPageFrame*, const SwRect& ) 
const override;
+    void AddSubsidiaryLinesBounds(const SwViewShell& rViewShell, 
RectangleVector& rRects) const;
 };
 
 /// Header in the document layout, inside a page.
diff --git a/sw/source/core/inc/pagefrm.hxx b/sw/source/core/inc/pagefrm.hxx
index d85ddaecd116..53bf27a24bbc 100644
--- a/sw/source/core/inc/pagefrm.hxx
+++ b/sw/source/core/inc/pagefrm.hxx
@@ -123,6 +123,8 @@ class SW_DLLPUBLIC SwPageFrame final: public 
SwFootnoteBossFrame
     /// Calculate the content height of a page (without columns).
     size_t GetContentHeight(const tools::Long nTop, const tools::Long nBottom) 
const;
 
+    std::vector<basegfx::B2DPolygon> GetSubsidiaryLinesPolygons(const 
SwViewShell& rViewShell) const;
+
 public:
     SwPageFrame( SwFrameFormat*, SwFrame*, SwPageDesc* );
 
@@ -189,6 +191,7 @@ public:
 
     void PaintDecorators( ) const;
     virtual void PaintSubsidiaryLines( const SwPageFrame*, const SwRect& ) 
const override;
+    void AddSubsidiaryLinesBounds(const SwViewShell& rShell, RectangleVector& 
rRects) const;
     virtual void PaintBreak() const override;
 
     /// Paint line number etc.
diff --git a/sw/source/core/layout/paintfrm.cxx 
b/sw/source/core/layout/paintfrm.cxx
index 117ac8eb5e61..7c757e4d19ca 100644
--- a/sw/source/core/layout/paintfrm.cxx
+++ b/sw/source/core/layout/paintfrm.cxx
@@ -18,6 +18,7 @@
  */
 
 #include <utility>
+#include <vcl/canvastools.hxx>
 #include <vcl/lazydelete.hxx>
 #include <sfx2/docfile.hxx>
 #include <sfx2/printer.hxx>
@@ -6969,12 +6970,10 @@ static void lcl_RefreshLine( const SwLayoutFrame *pLay,
     }
 }
 
-static drawinglayer::primitive2d::Primitive2DContainer 
lcl_CreatePageAreaDelimiterPrimitives(
-        const SwRect& rRect )
+static std::vector<basegfx::B2DPolygon> 
lcl_CreatePageAreaDelimiterPolygons(const SwRect& rRect)
 {
-    drawinglayer::primitive2d::Primitive2DContainer aSeq( 4 );
+    std::vector<basegfx::B2DPolygon> aPolygons;
 
-    basegfx::BColor aLineColor = 
SwViewOption::GetCurrentViewOptions().GetDocBoundariesColor().getBColor();
     double nLineLength = 200.0; // in Twips
 
     Point aPoints[] = { rRect.TopLeft(), rRect.TopRight(), 
rRect.BottomRight(), rRect.BottomLeft() };
@@ -6994,30 +6993,39 @@ static drawinglayer::primitive2d::Primitive2DContainer 
lcl_CreatePageAreaDelimit
         aPolygon.append( aBPoint );
         aPolygon.append( aBPoint + aVertVector * nLineLength );
 
-        aSeq[i] = new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
-                    std::move(aPolygon), aLineColor );
+        aPolygons.emplace_back(aPolygon);
     }
 
-    return aSeq;
+    return aPolygons;
 }
 
-static drawinglayer::primitive2d::Primitive2DContainer 
lcl_CreateRectangleDelimiterPrimitives (
-        const SwRect& rRect )
+static drawinglayer::primitive2d::Primitive2DContainer 
lcl_CreateDelimiterPrimitives(
+    const std::vector<basegfx::B2DPolygon>& rPolygons)
 {
-    drawinglayer::primitive2d::Primitive2DContainer aSeq( 1 );
+    drawinglayer::primitive2d::Primitive2DContainer aSeq(rPolygons.size());
+
     basegfx::BColor aLineColor = 
SwViewOption::GetCurrentViewOptions().GetDocBoundariesColor().getBColor();
+    for (size_t i = 0; i < rPolygons.size(); ++i)
+        aSeq[i] = new 
drawinglayer::primitive2d::PolygonHairlinePrimitive2D(rPolygons[i], aLineColor);
 
-    basegfx::B2DPolygon aPolygon;
-    aPolygon.append( basegfx::B2DPoint( rRect.Left(), rRect.Top() ) );
-    aPolygon.append( basegfx::B2DPoint( rRect.Right(), rRect.Top() ) );
-    aPolygon.append( basegfx::B2DPoint( rRect.Right(), rRect.Bottom() ) );
-    aPolygon.append( basegfx::B2DPoint( rRect.Left(), rRect.Bottom() ) );
-    aPolygon.setClosed( true );
+    return aSeq;
+}
 
-    aSeq[0] = new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
-                std::move(aPolygon), aLineColor );
+static std::vector<basegfx::B2DPolygon> 
lcl_CreateRectangleDelimiterPolygons(const SwRect& rRect)
+{
+    std::vector<basegfx::B2DPolygon> aRet(1);
+    aRet[0].append( basegfx::B2DPoint( rRect.Left(), rRect.Top() ) );
+    aRet[0].append( basegfx::B2DPoint( rRect.Right(), rRect.Top() ) );
+    aRet[0].append( basegfx::B2DPoint( rRect.Right(), rRect.Bottom() ) );
+    aRet[0].append( basegfx::B2DPoint( rRect.Left(), rRect.Bottom() ) );
+    aRet[0].setClosed( true );
+    return aRet;
+}
 
-    return aSeq;
+static drawinglayer::primitive2d::Primitive2DContainer 
lcl_CreateRectangleDelimiterPrimitives (
+        const SwRect& rRect )
+{
+    return 
lcl_CreateDelimiterPrimitives(lcl_CreateRectangleDelimiterPolygons(rRect));
 }
 
 static drawinglayer::primitive2d::Primitive2DContainer 
lcl_CreateColumnAreaDelimiterPrimitives(
@@ -7052,14 +7060,12 @@ static drawinglayer::primitive2d::Primitive2DContainer 
lcl_CreateColumnAreaDelim
     return aSeq;
 }
 
-void SwPageFrame::PaintSubsidiaryLines( const SwPageFrame *,
-                                        const SwRect & ) const
+std::vector<basegfx::B2DPolygon> SwPageFrame::GetSubsidiaryLinesPolygons(const 
SwViewShell& rViewShell) const
 {
-    if (!gProp.pSGlobalShell->GetViewOptions()->IsDocBoundaries())
-        return;
+    std::vector<basegfx::B2DPolygon> aPolygons;
 
-    if ( gProp.pSGlobalShell->IsHeaderFooterEdit() )
-        return;
+    if (!rViewShell.GetViewOptions()->IsDocBoundaries())
+        return aPolygons;
 
     const SwFrame* pLay = Lower();
     const SwFrame* pFootnoteCont = nullptr;
@@ -7079,10 +7085,64 @@ void SwPageFrame::PaintSubsidiaryLines( const 
SwPageFrame *,
     if ( pFootnoteCont )
         aArea.AddBottom( pFootnoteCont->getFrameArea().Bottom() - 
aArea.Bottom() );
 
-    if ( !gProp.pSGlobalShell->GetViewOptions()->IsViewMetaChars( ) )
-        ProcessPrimitives( lcl_CreatePageAreaDelimiterPrimitives( aArea ) );
+    if (aArea.IsEmpty())
+        return aPolygons;
+
+    if (!rViewShell.GetViewOptions()->IsViewMetaChars())
+        aPolygons = lcl_CreatePageAreaDelimiterPolygons(aArea);
     else
-        ProcessPrimitives( lcl_CreateRectangleDelimiterPrimitives( aArea ) );
+        aPolygons = lcl_CreateRectangleDelimiterPolygons(aArea);
+
+    return aPolygons;
+}
+
+void SwPageFrame::PaintSubsidiaryLines(const SwPageFrame*, const SwRect&) const
+{
+    if (gProp.pSGlobalShell->IsHeaderFooterEdit())
+        return;
+
+    std::vector<basegfx::B2DPolygon> aPolygons = 
GetSubsidiaryLinesPolygons(*gProp.pSGlobalShell);
+    if (aPolygons.empty())
+        return;
+
+    ProcessPrimitives(lcl_CreateDelimiterPrimitives(aPolygons));
+}
+
+static void lclAddSubsidiaryLinesBounds(const 
std::vector<basegfx::B2DPolygon>& rPolygons, RectangleVector& rRects)
+{
+    for (const auto& rPolygon : rPolygons)
+    {
+        tools::Rectangle 
aRect(vcl::unotools::rectangleFromB2DRectangle(rPolygon.getB2DRange()));
+        aRect.expand(1);
+        if (basegfx::utils::isRectangle(rPolygon) && aRect.GetWidth() > 4 && 
aRect.GetHeight() > 4)
+        {
+            // turn hairline rectangle into four non-overlapping blocks that 
cover the borders
+            rRects.emplace_back(tools::Rectangle(Point(aRect.Left(), 
aRect.Top()), Size(aRect.GetWidth(), 2)));
+            rRects.emplace_back(tools::Rectangle(Point(aRect.Left(), 
aRect.Top() + 2), Size(2, aRect.GetHeight() - 4)));
+            rRects.emplace_back(tools::Rectangle(Point(aRect.Right() - 2, 
aRect.Top() + 2), Size(2, aRect.GetHeight() - 4)));
+            rRects.emplace_back(tools::Rectangle(Point(aRect.Left(), 
aRect.Top() + aRect.GetHeight() - 2), Size(aRect.GetWidth(), 2)));
+        }
+        else
+            rRects.emplace_back(aRect);
+    }
+}
+
+void SwPageFrame::AddSubsidiaryLinesBounds(const SwViewShell& rViewShell, 
RectangleVector& rRects) const
+{
+    lclAddSubsidiaryLinesBounds(GetSubsidiaryLinesPolygons(rViewShell), 
rRects);
+
+    const SwFrame *pLow = Lower();
+    while (pLow)
+    {
+        if (pLow->getFrameArea().HasArea())
+        {
+            if (pLow->IsHeaderFrame() || pLow->IsFooterFrame())
+            {
+                static_cast<const 
SwHeadFootFrame*>(pLow)->AddSubsidiaryLinesBounds(rViewShell, rRects);
+            }
+        }
+        pLow = pLow->GetNext();
+    }
 }
 
 void SwColumnFrame::PaintSubsidiaryLines( const SwPageFrame *,
@@ -7148,20 +7208,38 @@ void SwBodyFrame::PaintSubsidiaryLines( const 
SwPageFrame *,
 {
 }
 
-void SwHeadFootFrame::PaintSubsidiaryLines( const SwPageFrame *, const SwRect 
& ) const
+std::vector<basegfx::B2DPolygon> 
SwHeadFootFrame::GetSubsidiaryLinesPolygons(const SwViewShell& rViewShell) const
+{
+    std::vector<basegfx::B2DPolygon> aPolygons;
+
+    if (!rViewShell.GetViewOptions()->IsDocBoundaries())
+        return aPolygons;
+
+    SwRect aArea( getFramePrintArea() );
+    aArea.Pos() += getFrameArea().Pos();
+    if (!rViewShell.GetViewOptions()->IsViewMetaChars( ))
+        aPolygons = lcl_CreatePageAreaDelimiterPolygons(aArea);
+    else
+        aPolygons = lcl_CreateRectangleDelimiterPolygons(aArea);
+
+    return aPolygons;
+}
+
+void SwHeadFootFrame::PaintSubsidiaryLines(const SwPageFrame*, const SwRect&) 
const
 {
-    if (!gProp.pSGlobalShell->GetViewOptions()->IsDocBoundaries())
+    if (!gProp.pSGlobalShell->IsHeaderFooterEdit())
         return;
 
-    if ( gProp.pSGlobalShell->IsHeaderFooterEdit() )
-    {
-        SwRect aArea( getFramePrintArea() );
-        aArea.Pos() += getFrameArea().Pos();
-        if ( !gProp.pSGlobalShell->GetViewOptions()->IsViewMetaChars( ) )
-            ProcessPrimitives( lcl_CreatePageAreaDelimiterPrimitives( aArea ) 
);
-        else
-            ProcessPrimitives( lcl_CreateRectangleDelimiterPrimitives( aArea ) 
);
-    }
+    std::vector<basegfx::B2DPolygon> aPolygons = 
GetSubsidiaryLinesPolygons(*gProp.pSGlobalShell);
+    if (aPolygons.empty())
+        return;
+
+    ProcessPrimitives(lcl_CreateDelimiterPrimitives(aPolygons));
+}
+
+void SwHeadFootFrame::AddSubsidiaryLinesBounds(const SwViewShell& rViewShell, 
RectangleVector& rRects) const
+{
+    lclAddSubsidiaryLinesBounds(GetSubsidiaryLinesPolygons(rViewShell), 
rRects);
 }
 
 /**
diff --git a/sw/source/core/view/viewsh.cxx b/sw/source/core/view/viewsh.cxx
index 9074f43ab8b4..a77d0ccc8bcf 100644
--- a/sw/source/core/view/viewsh.cxx
+++ b/sw/source/core/view/viewsh.cxx
@@ -126,8 +126,22 @@ void SwViewShell::ToggleHeaderFooterEdit()
         mbHeaderFooterEdit = false;
     }
 
-    // Repaint everything
-    GetWin()->Invalidate();
+    InvalidatePageAndHFSubsidiaryLines();
+}
+
+// Invalidate Subsidiary Lines around headers/footers and page frames to 
repaint
+void SwViewShell::InvalidatePageAndHFSubsidiaryLines()
+{
+    RectangleVector aInvalidRects;
+    SwPageFrame *pPg = static_cast<SwPageFrame*>(GetLayout()->Lower());
+    while (pPg)
+    {
+        pPg->AddSubsidiaryLinesBounds(*this, aInvalidRects);
+        pPg = static_cast<SwPageFrame*>(pPg->GetNext());
+    }
+
+    for (const auto &rRect : aInvalidRects)
+        GetWin()->Invalidate(rRect);
 }
 
 void SwViewShell::setOutputToWindow(bool bOutputToWindow)

Reply via email to