desktop/inc/lib/init.hxx                        |    8 ++++
 desktop/qa/data/create-view-omit-invalidate.ods |binary
 desktop/qa/desktop_lib/test_desktop_lib.cxx     |   42 ++++++++++++++++++++++++
 desktop/source/lib/init.cxx                     |   16 ++++++++-
 4 files changed, 65 insertions(+), 1 deletion(-)

New commits:
commit 3948462325e921c5702b2b73b22ff6523b28bc2d
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Mon May 5 14:27:11 2025 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Tue May 6 15:36:47 2025 +0200

    cool#11826 desktop lok: inform new view about already painted areas
    
    Open the Calc bugdoc, sheet 1 is visible. Open a 2nd view, still on
    sheet 1. Switch to sheet 2 in view 1, change the call, the sheet 1 in
    view 2 doesn't update.
    
    What happens is that view 1 performs its rendering of sheet 1, then view
    2 is created, so once sheet 2 is changed in view 1, we think that there
    is no need to invalidate view 2, since it was never painted, since
    commit b95a6816555396661d90da02e844d2848b1da3bf (cool#11254 desktop lok:
    avoid invalidations if no tiles are sent, 2025-03-05).
    
    Fix the problem by extending doc_registerCallback() to take the info
    about already painted areas on view creation: now that the view creation
    is handled and the view update is done in
    LibLODocument_Impl::updateViewsForPaintedTile(), the info about already
    painted tiles is again synchronized in all views with the same view
    render state.
    
    Also mention CanonicalViewId in comments, because that's term we use for
    views with the same view render state, so git grep can find both
    locations.
    
    Change-Id: I7698830e1070e0bbe0c186d41ce83c8e22eb7049
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/184989
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins

diff --git a/desktop/inc/lib/init.hxx b/desktop/inc/lib/init.hxx
index e42f378f757e..04a72802e4f5 100644
--- a/desktop/inc/lib/init.hxx
+++ b/desktop/inc/lib/init.hxx
@@ -117,6 +117,14 @@ namespace desktop {
 
         DESKTOP_DLLPUBLIC void tilePainted(int nPart, int nMode, const 
tools::Rectangle& rRectangle);
         const OString& getViewRenderState() const { return m_aViewRenderState; 
}
+        const std::map<int, std::map<int, tools::Rectangle>>& 
getPaintedTiles() const
+        {
+            return m_aPaintedTiles;
+        }
+        void setPaintedTiles(const std::map<int, std::map<int, 
tools::Rectangle>>& rPaintedTiles)
+        {
+            m_aPaintedTiles = rPaintedTiles;
+        }
 
         // SfxLockCallbackInterface
         virtual void libreOfficeKitViewCallback(int nType, const OString& 
pPayload) override;
diff --git a/desktop/qa/data/create-view-omit-invalidate.ods 
b/desktop/qa/data/create-view-omit-invalidate.ods
new file mode 100644
index 000000000000..a3f065dff1dc
Binary files /dev/null and b/desktop/qa/data/create-view-omit-invalidate.ods 
differ
diff --git a/desktop/qa/desktop_lib/test_desktop_lib.cxx 
b/desktop/qa/desktop_lib/test_desktop_lib.cxx
index 8fd22a443926..8cb3b8d11058 100644
--- a/desktop/qa/desktop_lib/test_desktop_lib.cxx
+++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx
@@ -181,6 +181,7 @@ public:
     void testOmitInvalidate();
     void test2ViewsOmitInvalidate();
     void testPaintTileOmitInvalidate();
+    void testCreateViewOmitInvalidate();
     void testInput();
     void testRedlineWriter();
     void testRedlineCalc();
@@ -256,6 +257,7 @@ public:
     CPPUNIT_TEST(testOmitInvalidate);
     CPPUNIT_TEST(test2ViewsOmitInvalidate);
     CPPUNIT_TEST(testPaintTileOmitInvalidate);
+    CPPUNIT_TEST(testCreateViewOmitInvalidate);
     CPPUNIT_TEST(testInput);
     CPPUNIT_TEST(testRedlineWriter);
     CPPUNIT_TEST(testRedlineCalc);
@@ -2376,6 +2378,46 @@ void DesktopLOKTest::testPaintTileOmitInvalidate()
     CPPUNIT_ASSERT(aView.m_bTilesInvalidated);
 }
 
+void DesktopLOKTest::testCreateViewOmitInvalidate()
+{
+    // Given a document with 2 views: view 1 renders sheet One, then view 2 
gets created and finally
+    // view 1 switches to sheet Two:
+    comphelper::LibreOfficeKit::setPartInInvalidation(true);
+    comphelper::ScopeGuard aGuard([]()
+    {
+        comphelper::LibreOfficeKit::setPartInInvalidation(false);
+    });
+    LibLODocument_Impl* pDocument = loadDoc("create-view-omit-invalidate.ods");
+    pDocument->m_pDocumentClass->initializeForRendering(pDocument, nullptr);
+    ViewCallback aView1(pDocument);
+    int nView1 = pDocument->m_pDocumentClass->getView(pDocument);
+    const int nCanvasWidth = 256;
+    const int nCanvasHeight = 256;
+    std::array<sal_uInt8, nCanvasWidth * nCanvasHeight * 4> aPixels;
+    pDocument->m_pDocumentClass->paintTile(pDocument, aPixels.data(), 
nCanvasWidth, nCanvasHeight, 0, 0, 3840, 3840);
+    pDocument->m_pDocumentClass->createView(pDocument);
+    pDocument->m_pDocumentClass->initializeForRendering(pDocument, nullptr);
+    ViewCallback aView2(pDocument);
+    pDocument->m_pDocumentClass->setView(pDocument, nView1);
+    pDocument->m_pDocumentClass->setPart(pDocument, 1);
+    Scheduler::ProcessEventsToIdle();
+    aView1.m_bTilesInvalidated = false;
+    aView2.m_bTilesInvalidated = false;
+
+    // When pressing a key in view 1, on sheet Two:
+    pDocument->pClass->postKeyEvent(pDocument, LOK_KEYEVENT_KEYINPUT, 'x', 0);
+    pDocument->pClass->postKeyEvent(pDocument, LOK_KEYEVENT_KEYUP, 'x', 0);
+    pDocument->pClass->postKeyEvent(pDocument, LOK_KEYEVENT_KEYINPUT, 0, 
KEY_RETURN);
+    pDocument->pClass->postKeyEvent(pDocument, LOK_KEYEVENT_KEYUP, 0, 
KEY_RETURN);
+    Scheduler::ProcessEventsToIdle();
+
+    // Then make sure that both views are invalidated:
+    CPPUNIT_ASSERT(aView1.m_bTilesInvalidated);
+    // Without the accompanying fix in place, this test would have failed, the 
2nd view was not
+    // invalidated when it was created after a paintTile().
+    CPPUNIT_ASSERT(aView2.m_bTilesInvalidated);
+}
+
 void DesktopLOKTest::testPaintPartTileDifferentSchemes()
 {
     Color aDarkColor(0x1c, 0x1c, 0x1c);
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index d445eaab46f9..5ddfbac35557 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -4503,6 +4503,7 @@ void LibLODocument_Impl::updateViewsForPaintedTile(int 
nOrigViewId, int nPart, i
         return;
     }
 
+    // Update info about painted tiles in other views that have the same 
CanonicalViewId.
     const OString& rViewRenderState = it->second->getViewRenderState();
     for (const auto& rHandler : mpCallbackFlushHandlers)
     {
@@ -4650,7 +4651,8 @@ static void doc_registerCallback(LibreOfficeKitDocument* 
pThis,
         }
     }
 
-    pDocument->mpCallbackFlushHandlers[nView] = 
std::make_shared<CallbackFlushHandler>(pThis, pCallback, pData);
+    auto pCallbackFlushHandler = std::make_shared<CallbackFlushHandler>(pThis, 
pCallback, pData);
+    pDocument->mpCallbackFlushHandlers[nView] = pCallbackFlushHandler;
 
     if (pCallback != nullptr)
     {
@@ -4684,6 +4686,18 @@ static void doc_registerCallback(LibreOfficeKitDocument* 
pThis,
             pCallback(LOK_CALLBACK_FONTS_MISSING, sPayload.getStr(), pData);
             pDocument->maFontsMissing.clear();
         }
+
+        // Try to take info about already painted tiles from an other view 
that has the same
+        // CanonicalViewId.
+        const OString& rViewRenderState = 
pCallbackFlushHandler->getViewRenderState();
+        for (const auto& rHandler : pDocument->mpCallbackFlushHandlers)
+        {
+            if (rHandler.second->getViewRenderState() == rViewRenderState && 
rHandler.first != nId)
+            {
+                
pCallbackFlushHandler->setPaintedTiles(rHandler.second->getPaintedTiles());
+                break;
+            }
+        }
     }
     else
     {

Reply via email to