sw/qa/extras/tiledrendering2/tiledrendering2.cxx |   39 +++++++++++++++++++++++
 sw/source/core/layout/layact.cxx                 |   13 ++++++-
 2 files changed, 50 insertions(+), 2 deletions(-)

New commits:
commit e1e77b313c9fe0fff814384a67de415e33c8b27f
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Thu Aug 8 09:31:59 2024 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Thu Aug 8 10:44:57 2024 +0200

    cool#9735 sw lok: take LOK vis area into account when deciding idle layout
    
    E.g. paste into a paragraph that is part of an Arabic numbering in the
    bugdoc (or perform any other action that invalidates all pages), the
    desktop case does a synchronous layout of the visible page and does the
    layout for the other pages in idle.
    
    The LOK case is worse, there we do the entire layout synchronously,
    which can result in a 274 ms hang for the bugdoc. The root of this is
    that the visible area in Writer is used both to decide if invalidations
    are necessary for that area (this is wanted in the LOK case) and also to
    decide if the layout has to be done synchronously (this is not wanted in
    the LOK case).
    
    Fix the problem by taking the LOK visible area from SwViewShell and
    work with that if possible. This reduces the time spent in the
    synchronous layout to 4 ms.
    
    This should help the interactive editing of large Writer documents in
    general, but pasting into a numbering is a good example, because there
    you can precisely measure if just 1 page is laid out instantly or all
    pages.
    
    Change-Id: Ia423079c76f8d93263a023da4bfbf2a9a5ccbf33
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/171619
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins

diff --git a/sw/qa/extras/tiledrendering2/tiledrendering2.cxx 
b/sw/qa/extras/tiledrendering2/tiledrendering2.cxx
index efe53e64bcec..0aba4ef6ab38 100644
--- a/sw/qa/extras/tiledrendering2/tiledrendering2.cxx
+++ b/sw/qa/extras/tiledrendering2/tiledrendering2.cxx
@@ -22,6 +22,7 @@
 #include <test/lokcallback.hxx>
 #include <sfx2/msgpool.hxx>
 #include <comphelper/string.hxx>
+#include <vcl/scheduler.hxx>
 
 #include <wrtsh.hxx>
 #include <view.hxx>
@@ -31,6 +32,7 @@
 #include <rootfrm.hxx>
 #include <swmodule.hxx>
 #include <swdll.hxx>
+#include <pagefrm.hxx>
 
 namespace
 {
@@ -265,6 +267,43 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testPasteInvalidateNumRulesBullet)
     SwFrame* pPage3 = pPage2->GetNext();
     
CPPUNIT_ASSERT(!aView.m_aInvalidations.Overlaps(pPage3->getFrameArea().SVRect()));
 }
+
+CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testAsyncLayout)
+{
+    // Given a document with 3 pages, the first page is visible:
+    SwXTextDocument* pXTextDocument = createDoc();
+    CPPUNIT_ASSERT(pXTextDocument);
+    ViewCallback aView;
+    SwDocShell* pDocShell = getSwDocShell();
+    SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
+    pWrtShell->InsertPageBreak();
+    pWrtShell->InsertPageBreak();
+    SwRootFrame* pLayout = pWrtShell->GetLayout();
+    SwPageFrame* pPage1 = pLayout->GetLower()->DynCastPageFrame();
+    pWrtShell->setLOKVisibleArea(pPage1->getFrameArea().SVRect());
+
+    // When all pages get invalidated:
+    pWrtShell->StartAllAction();
+    pPage1->InvalidateContent();
+    SwPageFrame* pPage2 = pPage1->GetNext()->DynCastPageFrame();
+    pPage2->InvalidateContent();
+    SwPageFrame* pPage3 = pPage2->GetNext()->DynCastPageFrame();
+    pPage3->InvalidateContent();
+    pWrtShell->EndAllAction();
+
+    // Then make sure only the first page gets a synchronous layout:
+    CPPUNIT_ASSERT(!pPage1->IsInvalidContent());
+    CPPUNIT_ASSERT(pPage2->IsInvalidContent());
+    CPPUNIT_ASSERT(pPage3->IsInvalidContent());
+
+    // And then processing all idle events:
+    Scheduler::ProcessEventsToIdle();
+
+    // Then make sure all pages get an async layout:
+    CPPUNIT_ASSERT(!pPage1->IsInvalidContent());
+    CPPUNIT_ASSERT(!pPage2->IsInvalidContent());
+    CPPUNIT_ASSERT(!pPage3->IsInvalidContent());
+}
 }
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/core/layout/layact.cxx b/sw/source/core/layout/layact.cxx
index f63555890f06..cfd1afbff88f 100644
--- a/sw/source/core/layout/layact.cxx
+++ b/sw/source/core/layout/layact.cxx
@@ -68,6 +68,7 @@
 #include <comphelper/scopeguard.hxx>
 #include <vector>
 #include <comphelper/diagnose_ex.hxx>
+#include <comphelper/lok.hxx>
 
 void SwLayAction::CheckWaitCursor()
 {
@@ -547,7 +548,8 @@ void SwLayAction::InternalAction(OutputDevice* 
pRenderContext)
         }
         m_pOptTab = nullptr;
 
-        // No Shortcut for Idle or CalcLayout
+        // No Shortcut for Idle or CalcLayout. The shortcut case means that in 
case the page is not
+        // inside the visible area, then the synchronous (not idle) layout 
skips the page.
         const bool bTakeShortcut = !IsIdle() && !IsComplete() && 
IsShortCut(pPage);
 
         m_pRoot->DeleteEmptySct();
@@ -1041,7 +1043,14 @@ bool SwLayAction::IsShortCut( SwPageFrame *&prPage )
             return false;
     }
 
-    const SwRect &rVis = m_pImp->GetShell()->VisArea();
+    // Decide if prPage is visible, i.e. part of the visible area.
+    const SwRect &rVisArea = m_pImp->GetShell()->VisArea();
+    // LOK case: VisArea() is the entire document and getLOKVisibleArea() may 
contain the actual
+    // visible area.
+    SwRect aLokVisArea(m_pImp->GetShell()->getLOKVisibleArea());
+    bool bUseLokVisArea = comphelper::LibreOfficeKit::isActive() && 
!aLokVisArea.IsEmpty();
+    const SwRect& rVis = bUseLokVisArea ? aLokVisArea : rVisArea;
+
     if ( (prPage->getFrameArea().Top() >= rVis.Bottom()) ||
          (prPage->getFrameArea().Left()>= rVis.Right()) )
     {

Reply via email to