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 {