include/svx/svdmodel.hxx                          |    3 ++
 include/svx/svdpntv.hxx                           |    1 
 svx/source/svdraw/svdmodel.cxx                    |    1 
 svx/source/svdraw/svdpntv.cxx                     |   10 +++++++
 sw/qa/extras/tiledrendering/data/3pages-shape.odt |binary
 sw/qa/extras/tiledrendering/tiledrendering2.cxx   |   29 ++++++++++++++++++++++
 sw/source/core/layout/layact.cxx                  |   17 ++++++++++++
 7 files changed, 61 insertions(+)

New commits:
commit 15ffc9e525aef38f27f80d9e7f76cdcbbcbf6e23
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Thu May 15 09:34:25 2025 +0200
Commit:     Caolán McNamara <caolan.mcnam...@collabora.com>
CommitDate: Thu May 15 12:12:13 2025 +0200

    cool#11942 svx lok: handle Writer idle status when starting the paint view 
idle
    
    The bugdoc is similar to cool#11785, i.e. a document of 3-400 pages, but
    the content is reasonably simple, mostly plain text and bullet points.
    The document has a shape, though. Loading this document in COOL does a
    full sync layout on load, which is reported to take ~9s on a slower
    machine and it takes >1s for me locally (after doc load, before the
    render of the first page).
    
    It seems what happens is that idle layout is started, but it's not
    interrupted, because moving content between pages in
    SwLayAction::Action(), called from the SwLayIdle ctor calls into
    SdrPaintView::Notify(), which starts a high priority "idle", so the LOK
    client thinks it should not interrupt core jobs, so the idle layout
    first completes, and only then we paint the first tile.
    
    Fix the problem by adjusting the priority of
    SdrPaintView::maComeBackIdle dynamically. Add a flag in the draw model
    to know when we're inside the Writer idle layout and once the svx/ idle
    is started, lower the priority in case that's invoked from inside the
    Writer idle layout. This gives the LOK client a way to interrupt the
    Writer idle layout (via the anyInput callback), now that it seems core
    has no high priority jobs in the scheduler.  Size of the time window
    between the end of doc load and the start of the first tile render,
    before: 1617 ms. After: 182 ms
    
    An alternative approach I considered is to interact with the
    SdrPaintView that belongs to the current Writer view, but that won't
    work. There are typically 2 draw views active right after document
    load, one created in SwViewShellImp::MakeDrawView(), but there is also
    an additional hidden view created in the SvxDrawPage ctor for UNO
    purposes, so if we don't go via SdrModel, we would have to notify both
    views that we're entering / leaving the Writer idle layout, which looks
    more complicated than what this patch does.
    
    Change-Id: I115ba2c152fe7283804cde564afd511f9fbff707
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/185344
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Tested-by: Caolán McNamara <caolan.mcnam...@collabora.com>

diff --git a/include/svx/svdmodel.hxx b/include/svx/svdmodel.hxx
index b0d8bd7b36a5..0c078e20ac96 100644
--- a/include/svx/svdmodel.hxx
+++ b/include/svx/svdmodel.hxx
@@ -202,6 +202,7 @@ protected:
     sal_uInt16          m_nPageNumsDirtyFrom = SAL_MAX_UINT16;
     sal_uInt16          m_nMasterPageNumsDirtyFrom = SAL_MAX_UINT16;
     bool                m_bIsWriter:1;        // to clean up pMyPool from 303a
+    bool                m_bIsWriterIdle:1;
     bool                m_bThemedControls:1;  // If false UnoControls should 
not use theme colors
     bool                mbUndoEnabled:1;  // If false no undo is recorded or 
we are during the execution of an undo action
     bool                mbChanged:1;
@@ -584,6 +585,8 @@ public:
     void disposeOutliner( std::unique_ptr<SdrOutliner> pOutliner );
 
     bool IsWriter() const { return m_bIsWriter; }
+    void SetWriterIdle(bool bIsWriterIdle) { m_bIsWriterIdle = bIsWriterIdle; }
+    bool IsWriterIdle() const { return m_bIsWriterIdle; }
 
     bool IsPDFDocument() const { return m_bIsPDFDocument; }
     void setPDFDocument(bool bIsPDFDocument)
diff --git a/include/svx/svdpntv.hxx b/include/svx/svdpntv.hxx
index af03e455914c..d15a12415f6d 100644
--- a/include/svx/svdpntv.hxx
+++ b/include/svx/svdpntv.hxx
@@ -244,6 +244,7 @@ public:
     SdrPaintWindow* GetPaintWindow(sal_uInt32 nIndex) const;
     // Replacement for GetWin(0), may return 0L (!)
     OutputDevice* GetFirstOutputDevice() const;
+    const Idle& GetComeBackIdle() const { return maComeBackIdle; };
 
 private:
     DECL_DLLPRIVATE_LINK(ImpComeBackHdl, Timer*, void);
diff --git a/svx/source/svdraw/svdmodel.cxx b/svx/source/svdraw/svdmodel.cxx
index 5d83be0ebe10..1e74a03a3b02 100644
--- a/svx/source/svdraw/svdmodel.cxx
+++ b/svx/source/svdraw/svdmodel.cxx
@@ -129,6 +129,7 @@ SdrModel::SdrModel(SfxItemPool* pPool, 
comphelper::IEmbeddedHelper* pEmbeddedHel
     , m_pLinkManager(nullptr)
     , m_nUndoLevel(0)
     , m_bIsWriter(true)
+    , m_bIsWriterIdle(false)
     , m_bThemedControls(true)
     , mbUndoEnabled(true)
     , mbChanged(false)
diff --git a/svx/source/svdraw/svdpntv.cxx b/svx/source/svdraw/svdpntv.cxx
index 75eca2fb83c0..53373de6acee 100644
--- a/svx/source/svdraw/svdpntv.cxx
+++ b/svx/source/svdraw/svdpntv.cxx
@@ -214,6 +214,16 @@ void SdrPaintView::Notify(SfxBroadcaster& rBC, const 
SfxHint& rHint)
         if (bObjChg)
         {
             mbSomeObjChgdFlag=true;
+            const SdrModel& rModel = GetModel();
+            if (rModel.IsWriterIdle())
+            {
+                // We're inside Writer idle layout: don't pick a high priority.
+                maComeBackIdle.SetPriority(TaskPriority::DEFAULT_IDLE);
+            }
+            else
+            {
+                maComeBackIdle.SetPriority(TaskPriority::REPAINT);
+            }
             maComeBackIdle.Start();
         }
     }
diff --git a/sw/qa/extras/tiledrendering/data/3pages-shape.odt 
b/sw/qa/extras/tiledrendering/data/3pages-shape.odt
new file mode 100644
index 000000000000..27d377887d9a
Binary files /dev/null and b/sw/qa/extras/tiledrendering/data/3pages-shape.odt 
differ
diff --git a/sw/qa/extras/tiledrendering/tiledrendering2.cxx 
b/sw/qa/extras/tiledrendering/tiledrendering2.cxx
index bfd5c295a1a7..36c09a20d66a 100644
--- a/sw/qa/extras/tiledrendering/tiledrendering2.cxx
+++ b/sw/qa/extras/tiledrendering/tiledrendering2.cxx
@@ -37,6 +37,8 @@
 #include <docsh.hxx>
 #include <wrtsh.hxx>
 #include <swtestviewcallback.hxx>
+#include <viewimp.hxx>
+#include <dview.hxx>
 
 namespace
 {
@@ -778,6 +780,33 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, 
testSpellcheckVisibleArea)
     CPPUNIT_ASSERT(pPage2->IsInvalidSpelling());
     CPPUNIT_ASSERT(pPage3->IsInvalidSpelling());
 }
+
+CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testIdleLayoutShape)
+{
+    // Given a loaded document with a defined viewport:
+    awt::Rectangle aVisibleArea{ 0, 0, 12240, 15840 };
+    comphelper::LibreOfficeKit::setInitialClientVisibleArea(aVisibleArea);
+    comphelper::ScopeGuard g([] { 
comphelper::LibreOfficeKit::setInitialClientVisibleArea({}); });
+    OUString aURL = createFileURL(u"3pages-shape.odt");
+    UnoApiXmlTest::loadFromURL(aURL);
+
+    // When doing idle layout:
+    AnyInputCallback aAnyInput;
+    SwDocShell* pDocShell = getSwDocShell();
+    SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
+    pWrtShell->LayoutIdle();
+
+    // Then make sure that the draw task started during idle layout has no 
high priority, either:
+    SdrPaintView* pDrawView = pWrtShell->Imp()->GetDrawView();
+    CPPUNIT_ASSERT(pDrawView);
+    const Idle& rDrawIdle = pDrawView->GetComeBackIdle();
+    CPPUNIT_ASSERT(rDrawIdle.IsActive());
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected greater than: 4
+    // - Actual  : 4
+    // i.e. the priority was TaskPriority::REPAINT instead of 
TaskPriority::DEFAULT_IDLE.
+    CPPUNIT_ASSERT_GREATER(TaskPriority::REPAINT, rDrawIdle.GetPriority());
+}
 }
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/core/layout/layact.cxx b/sw/source/core/layout/layact.cxx
index 0000c3b15fac..bba7a93f6289 100644
--- a/sw/source/core/layout/layact.cxx
+++ b/sw/source/core/layout/layact.cxx
@@ -69,6 +69,7 @@
 #include <vector>
 #include <comphelper/diagnose_ex.hxx>
 #include <comphelper/lok.hxx>
+#include <drawdoc.hxx>
 
 void SwLayAction::CheckWaitCursor()
 {
@@ -2405,7 +2406,23 @@ SwLayIdle::SwLayIdle( SwRootFrame *pRt, SwViewShellImp 
*pI ) :
             aAction.SetInputType( VCL_INPUT_ANY & 
VclInputFlags(~VclInputFlags::TIMER) );
             aAction.SetIdle( true );
             aAction.SetWaitAllowed( false );
+
+            SdrModel* pSdrModel = 
m_pImp->GetShell()->getIDocumentDrawModelAccess().GetDrawModel();
+            bool bSdrModelIdle{};
+            if (pSdrModel)
+            {
+                // Let the draw views know that we're inside the idle layout.
+                bSdrModelIdle = pSdrModel->IsWriterIdle();
+                pSdrModel->SetWriterIdle(true);
+            }
+
             aAction.Action(m_pImp->GetShell()->GetOut());
+
+            if (pSdrModel)
+            {
+                pSdrModel->SetWriterIdle(bSdrModelIdle);
+            }
+
             bInterrupt = aAction.IsInterrupt();
         }
 

Reply via email to