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()) ) {