desktop/qa/desktop_lib/test_desktop_lib.cxx | 12 ++++ desktop/source/lib/init.cxx | 49 +++++++++++++++---- sw/inc/viscrs.hxx | 2 sw/source/core/crsr/viscrs.cxx | 70 ++++++++++++++++++++++------ sw/source/uibase/uiview/viewsrch.cxx | 4 - sw/source/uibase/wrtsh/wrtsh4.cxx | 5 ++ test/source/lokcallback.cxx | 2 7 files changed, 116 insertions(+), 28 deletions(-)
New commits: commit 1d54cb6adfe0b8730298b39cb4f4b1c390ae1e8f Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Thu Oct 7 18:02:12 2021 +0200 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Mon Oct 25 19:30:49 2021 +0200 use pull model also for LOK text selection Make LOK_CALLBACK_TEXT_SELECTION, LOK_CALLBACK_TEXT_SELECTION_START, LOK_CALLBACK_TEXT_SELECTION_END and LOK_CALLBACK_TEXT_VIEW_SELECTION also use pull model, i.e. LO core will only set a flag and when CallbackFlushHandler needs the actual data it'll use getLOKPayload(). This again avoids a large number of messages passed to CallbackFlushHandler only for them to be sooner or later discarded. Change-Id: Ia7528039be996a6e9e8491b4eba3f4133582fa56 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/124147 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Luboš Luňák <l.lu...@collabora.com> diff --git a/desktop/qa/desktop_lib/test_desktop_lib.cxx b/desktop/qa/desktop_lib/test_desktop_lib.cxx index 495293b76246..6eb1f73bfcc7 100644 --- a/desktop/qa/desktop_lib/test_desktop_lib.cxx +++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx @@ -1634,6 +1634,7 @@ void DesktopLOKTest::testNotificationCompression() LibLODocument_Impl* pDocument = loadDoc("blank_text.odt"); std::vector<std::tuple<int, std::string>> notifs; std::unique_ptr<CallbackFlushHandler> handler(new CallbackFlushHandler(pDocument, callbackCompressionTest, ¬ifs)); + handler->setViewId(SfxLokHelper::getView()); handler->queue(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR, ""); // 0 handler->queue(LOK_CALLBACK_TEXT_SELECTION, "15, 25, 15, 10"); // Superseded. @@ -1729,6 +1730,7 @@ void DesktopLOKTest::testTileInvalidationCompression() { std::vector<std::tuple<int, std::string>> notifs; std::unique_ptr<CallbackFlushHandler> handler(new CallbackFlushHandler(pDocument, callbackCompressionTest, ¬ifs)); + handler->setViewId(SfxLokHelper::getView()); handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, 239, 239, 0"); handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, 239, 239, 0"); @@ -1749,6 +1751,7 @@ void DesktopLOKTest::testTileInvalidationCompression() { std::vector<std::tuple<int, std::string>> notifs; std::unique_ptr<CallbackFlushHandler> handler(new CallbackFlushHandler(pDocument, callbackCompressionTest, ¬ifs)); + handler->setViewId(SfxLokHelper::getView()); handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, 239, 239, 0"); handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, 200, 200, 1"); // Different part @@ -1772,6 +1775,7 @@ void DesktopLOKTest::testTileInvalidationCompression() { std::vector<std::tuple<int, std::string>> notifs; std::unique_ptr<CallbackFlushHandler> handler(new CallbackFlushHandler(pDocument, callbackCompressionTest, ¬ifs)); + handler->setViewId(SfxLokHelper::getView()); handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, 239, 239, 0"); // 0 handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, 200, 200, 1"); // 1: Different part @@ -1798,6 +1802,7 @@ void DesktopLOKTest::testTileInvalidationCompression() { std::vector<std::tuple<int, std::string>> notifs; std::unique_ptr<CallbackFlushHandler> handler(new CallbackFlushHandler(pDocument, callbackCompressionTest, ¬ifs)); + handler->setViewId(SfxLokHelper::getView()); handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, 200, 200, 0"); // 0 handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, 100, 100, 1"); // 1: Different part @@ -1833,6 +1838,7 @@ void DesktopLOKTest::testTileInvalidationCompression() { std::vector<std::tuple<int, std::string>> notifs; std::unique_ptr<CallbackFlushHandler> handler(new CallbackFlushHandler(pDocument, callbackCompressionTest, ¬ifs)); + handler->setViewId(SfxLokHelper::getView()); handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, 239, 239, 0"); handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "EMPTY, 0"); @@ -1857,6 +1863,7 @@ void DesktopLOKTest::testPartInInvalidation() { std::vector<std::tuple<int, std::string>> notifs; std::unique_ptr<CallbackFlushHandler> handler(new CallbackFlushHandler(pDocument, callbackCompressionTest, ¬ifs)); + handler->setViewId(SfxLokHelper::getView()); handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "10, 10, 20, 10"); handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "20, 10, 20, 10"); @@ -1872,6 +1879,7 @@ void DesktopLOKTest::testPartInInvalidation() { std::vector<std::tuple<int, std::string>> notifs; std::unique_ptr<CallbackFlushHandler> handler(new CallbackFlushHandler(pDocument, callbackCompressionTest, ¬ifs)); + handler->setViewId(SfxLokHelper::getView()); handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "10, 10, 20, 10"); handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "40, 10, 20, 10"); @@ -1891,6 +1899,7 @@ void DesktopLOKTest::testPartInInvalidation() std::vector<std::tuple<int, std::string>> notifs; std::unique_ptr<CallbackFlushHandler> handler(new CallbackFlushHandler(pDocument, callbackCompressionTest, ¬ifs)); + handler->setViewId(SfxLokHelper::getView()); handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "10, 10, 20, 10, 0"); handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "20, 10, 20, 10, 0"); @@ -1909,6 +1918,7 @@ void DesktopLOKTest::testPartInInvalidation() std::vector<std::tuple<int, std::string>> notifs; std::unique_ptr<CallbackFlushHandler> handler(new CallbackFlushHandler(pDocument, callbackCompressionTest, ¬ifs)); + handler->setViewId(SfxLokHelper::getView()); handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "10, 10, 20, 10, 0"); handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "20, 10, 20, 10, 1"); @@ -1937,6 +1947,7 @@ void DesktopLOKTest::testBinaryCallback() { std::vector<std::tuple<int, std::string>> notifs; std::unique_ptr<CallbackFlushHandler> handler(new CallbackFlushHandler(pDocument, callbackBinaryCallbackTest, ¬ifs)); + handler->setViewId(SfxLokHelper::getView()); handler->queue(LOK_CALLBACK_INVALIDATE_TILES, rect1String.c_str()); @@ -1949,6 +1960,7 @@ void DesktopLOKTest::testBinaryCallback() { std::vector<std::tuple<int, std::string>> notifs; std::unique_ptr<CallbackFlushHandler> handler(new CallbackFlushHandler(pDocument, callbackBinaryCallbackTest, ¬ifs)); + handler->setViewId(SfxLokHelper::getView()); handler->libreOfficeKitViewInvalidateTilesCallback(&rect1, INT_MIN); diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx index b7bd3ca28a32..20916a4ebd3b 100644 --- a/desktop/source/lib/init.cxx +++ b/desktop/source/lib/init.cxx @@ -701,6 +701,10 @@ static bool isUpdatedType(int type) { switch (type) { + case LOK_CALLBACK_TEXT_SELECTION: + case LOK_CALLBACK_TEXT_SELECTION_START: + case LOK_CALLBACK_TEXT_SELECTION_END: + return true; default: return false; } @@ -712,6 +716,7 @@ static bool isUpdatedTypePerViewId(int type) { case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR: case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR: + case LOK_CALLBACK_TEXT_VIEW_SELECTION: return true; default: return false; @@ -2131,31 +2136,54 @@ void CallbackFlushHandler::enqueueUpdatedTypes() { if( m_updatedTypes.empty() && m_updatedTypesPerViewId.empty()) return; + assert(m_viewId >= 0); SfxViewShell* viewShell = SfxViewShell::GetFirst( false, [this](const SfxViewShell* shell) { return shell->GetViewShellId().get() == m_viewId; } ); assert(viewShell != nullptr); - for( size_t type = 0; type < m_updatedTypes.size(); ++type ) - { - if(m_updatedTypes[ type ]) + + // First move data to local structures, so that callbacks don't possibly modify it. + std::vector<bool> updatedTypes; + std::swap(updatedTypes, m_updatedTypes); + std::unordered_map<int, std::vector<PerViewIdData>> updatedTypesPerViewId; + std::swap(updatedTypesPerViewId, m_updatedTypesPerViewId); + + // Some types must always precede other types, for example + // LOK_CALLBACK_TEXT_SELECTION_START and LOK_CALLBACK_TEXT_SELECTION_END + // must always precede LOK_CALLBACK_TEXT_SELECTION if present. + // Only these types should be present (see isUpdatedType()) and should be processed in this order. + static const int orderedUpdatedTypes[] = { + LOK_CALLBACK_TEXT_SELECTION_START, LOK_CALLBACK_TEXT_SELECTION_END, LOK_CALLBACK_TEXT_SELECTION }; + // Only these types should be present (see isUpdatedTypePerViewId()) and (as of now) + // the order doesn't matter. + static const int orderedUpdatedTypesPerViewId[] = { + LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR, + LOK_CALLBACK_INVALIDATE_VIEW_CURSOR, + LOK_CALLBACK_TEXT_VIEW_SELECTION }; + + for( int type : orderedUpdatedTypes ) + { + if(o3tl::make_unsigned( type ) < updatedTypes.size() && updatedTypes[ type ]) { - assert(isUpdatedType( type )); enqueueUpdatedType( type, viewShell, m_viewId ); } } - for( auto it : m_updatedTypesPerViewId ) + + for( const auto& it : updatedTypesPerViewId ) { int viewId = it.first; const std::vector<PerViewIdData>& types = it.second; - for( size_t type = 0; type < types.size(); ++type ) + for( int type : orderedUpdatedTypesPerViewId ) { - if(types[ type ].set) + if(o3tl::make_unsigned( type ) < types.size() && types[ type ].set) { - assert(isUpdatedTypePerViewId( type )); SfxViewShell* sourceViewShell = viewShell; const int sourceViewId = types[ type ].sourceViewId; if( sourceViewId != m_viewId ) + { + assert(sourceViewId >= 0); sourceViewShell = SfxViewShell::GetFirst( false, [sourceViewId](const SfxViewShell* shell) { return shell->GetViewShellId().get() == sourceViewId; } ); + } if(sourceViewShell == nullptr) { SAL_INFO("lok", "View #" << sourceViewId << " no longer found for updated event [" << type << "]"); @@ -2165,13 +2193,13 @@ void CallbackFlushHandler::enqueueUpdatedTypes() } } } - m_updatedTypes.clear(); - m_updatedTypesPerViewId.clear(); } void CallbackFlushHandler::enqueueUpdatedType( int type, SfxViewShell* viewShell, int viewId ) { OString payload = viewShell->getLOKPayload( type, viewId ); + if(payload.isEmpty()) + return; // No actual payload to send. CallbackData callbackData(payload.getStr(), viewId); m_queue1.emplace_back(type); m_queue2.emplace_back(callbackData); @@ -2188,6 +2216,7 @@ void CallbackFlushHandler::Invoke() // Get any pending invalidate tile events. This will call our callbacks, // so it must be done before taking the mutex. + assert(m_viewId >= 0); if(SfxViewShell* viewShell = SfxViewShell::GetFirst( false, [this](const SfxViewShell* shell) { return shell->GetViewShellId().get() == m_viewId; } )) { diff --git a/sw/inc/viscrs.hxx b/sw/inc/viscrs.hxx index 3bd001bce074..b2ceb9c67c79 100644 --- a/sw/inc/viscrs.hxx +++ b/sw/inc/viscrs.hxx @@ -114,6 +114,8 @@ public: // Optional set the parameters pX, pY static void Get1PixelInLogic( const SwViewShell& rSh, tools::Long* pX = nullptr, tools::Long* pY = nullptr ); + + OString getLOKPayload(int nType, int nViewId) const; }; class SW_DLLPUBLIC SwShellCursor : public virtual SwCursor, public SwSelPaintRects diff --git a/sw/source/core/crsr/viscrs.cxx b/sw/source/core/crsr/viscrs.cxx index 26e3a4d1d30e..7d9564295fab 100644 --- a/sw/source/core/crsr/viscrs.cxx +++ b/sw/source/core/crsr/viscrs.cxx @@ -481,25 +481,14 @@ void SwSelPaintRects::Show(std::vector<OString>* pSelectionRectangles) // If pSelectionRectangles is set, we're just collecting the text selections -> don't emit start/end. if (!empty() && !pSelectionRectangles) { - // The selection may be a complex polygon, emit the logical - // start/end cursor rectangle of the selection as separate - // events, if there is a real selection. - // This can be used to easily show selection handles on the - // client side. SwRect aStartRect; SwRect aEndRect; FillStartEnd(aStartRect, aEndRect); if (aStartRect.HasArea()) - { - OString sRect = aStartRect.SVRect().toString(); - GetShell()->GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION_START, sRect.getStr()); - } + SfxLokHelper::notifyUpdate(GetShell()->GetSfxViewShell(), LOK_CALLBACK_TEXT_SELECTION_START); if (aEndRect.HasArea()) - { - OString sRect = aEndRect.SVRect().toString(); - GetShell()->GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION_END, sRect.getStr()); - } + SfxLokHelper::notifyUpdate(GetShell()->GetSfxViewShell(), LOK_CALLBACK_TEXT_SELECTION_END); } std::vector<OString> aRect; @@ -512,13 +501,64 @@ void SwSelPaintRects::Show(std::vector<OString>* pSelectionRectangles) OString sRect = comphelper::string::join("; ", aRect); if (!pSelectionRectangles) { - GetShell()->GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, sRect.getStr()); - SfxLokHelper::notifyOtherViews(GetShell()->GetSfxViewShell(), LOK_CALLBACK_TEXT_VIEW_SELECTION, "selection", sRect); + SfxLokHelper::notifyUpdate(GetShell()->GetSfxViewShell(),LOK_CALLBACK_TEXT_SELECTION); + SfxLokHelper::notifyOtherViewsUpdatePerViewId(GetShell()->GetSfxViewShell(), LOK_CALLBACK_TEXT_VIEW_SELECTION); } else pSelectionRectangles->push_back(sRect); } +OString SwSelPaintRects::getLOKPayload( int nType, int nViewId ) const +{ + switch( nType ) + { + case LOK_CALLBACK_TEXT_SELECTION_START: + case LOK_CALLBACK_TEXT_SELECTION_END: + { + // The selection may be a complex polygon, emit the logical + // start/end cursor rectangle of the selection as separate + // events, if there is a real selection. + // This can be used to easily show selection handles on the + // client side. + SwRect aStartRect; + SwRect aEndRect; + FillStartEnd(aStartRect, aEndRect); + + if( nType == LOK_CALLBACK_TEXT_SELECTION_START ) + { + if (aStartRect.HasArea()) + return aStartRect.SVRect().toString(); + return OString(); + } + else // LOK_CALLBACK_TEXT_SELECTION_END + { + if (aEndRect.HasArea()) + return aEndRect.SVRect().toString(); + return OString(); + } + } + break; + case LOK_CALLBACK_TEXT_SELECTION: + case LOK_CALLBACK_TEXT_VIEW_SELECTION: + { + std::vector<OString> aRect; + aRect.reserve(size()); + for (size_type i = 0; i < size(); ++i) + { + const SwRect& rRect = (*this)[i]; + aRect.push_back(rRect.SVRect().toString()); + } + OString sRect = comphelper::string::join("; ", aRect); + if( nType == LOK_CALLBACK_TEXT_SELECTION ) + return sRect; + else // LOK_CALLBACK_TEXT_VIEW_SELECTION + return SfxLokHelper::makePayloadJSON(GetShell()->GetSfxViewShell(), nViewId, "selection", sRect); + } + break; + } + abort(); +} + void SwSelPaintRects::HighlightInputField() { std::vector< basegfx::B2DRange > aInputFieldRanges; diff --git a/sw/source/uibase/uiview/viewsrch.cxx b/sw/source/uibase/uiview/viewsrch.cxx index 8db4ff0134bb..f9e83c53fac2 100644 --- a/sw/source/uibase/uiview/viewsrch.cxx +++ b/sw/source/uibase/uiview/viewsrch.cxx @@ -127,8 +127,8 @@ static void lcl_emitSearchResultCallbacks(SvxSearchItem const * pSearchItem, SwW if(bHighlightAll) { // FindAll disables this during find, do it once when done. - pWrtShell->GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, textSelection.getStr()); - SfxLokHelper::notifyOtherViews(pWrtShell->GetSfxViewShell(), LOK_CALLBACK_TEXT_VIEW_SELECTION, "selection", textSelection); + SfxLokHelper::notifyUpdate(pWrtShell->GetSfxViewShell(),LOK_CALLBACK_TEXT_SELECTION); + SfxLokHelper::notifyOtherViewsUpdatePerViewId(pWrtShell->GetSfxViewShell(), LOK_CALLBACK_TEXT_VIEW_SELECTION); } } diff --git a/sw/source/uibase/wrtsh/wrtsh4.cxx b/sw/source/uibase/wrtsh/wrtsh4.cxx index b80b41b41e54..0bafa1e75941 100644 --- a/sw/source/uibase/wrtsh/wrtsh4.cxx +++ b/sw/source/uibase/wrtsh/wrtsh4.cxx @@ -241,6 +241,11 @@ OString SwWrtShell::getLOKPayload(int nType, int nViewId) const case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR: case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR: return GetVisibleCursor()->getLOKPayload(nType, nViewId); + case LOK_CALLBACK_TEXT_SELECTION: + case LOK_CALLBACK_TEXT_SELECTION_START: + case LOK_CALLBACK_TEXT_SELECTION_END: + case LOK_CALLBACK_TEXT_VIEW_SELECTION: + return GetCursor_()->getLOKPayload( nType, nViewId ); } abort(); } diff --git a/test/source/lokcallback.cxx b/test/source/lokcallback.cxx index 8cda54424961..0f6970d2af9c 100644 --- a/test/source/lokcallback.cxx +++ b/test/source/lokcallback.cxx @@ -143,7 +143,7 @@ void TestLokCallbackWrapper::flushLOKData() return shell->GetViewShellId().get() == m_viewId; }); assert(viewShell != nullptr); - // First move data to local structures, so that notifyFromLOKCallback() doesn't modify it. + // First move data to local structures, so that callbacks don't possibly modify it. std::vector<int> updatedTypes; std::swap(updatedTypes, m_updatedTypes); std::vector<PerViewIdData> updatedTypesPerViewId;