desktop/qa/desktop_lib/test_desktop_lib.cxx |   12 ++++
 desktop/source/lib/init.cxx                 |   56 +++++++++++++++++-----
 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, 121 insertions(+), 30 deletions(-)

New commits:
commit 4bb6533d398cc76d7ff292a9e47dae87fac74f83
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:34 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/+/124146
    Tested-by: Jenkins
    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 cfa8e039a5d0..1144a5e48369 100644
--- a/desktop/qa/desktop_lib/test_desktop_lib.cxx
+++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx
@@ -1545,6 +1545,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, &notifs));
+    handler->setViewId(SfxLokHelper::getView());
 
     handler->queue(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR, ""); // 0
     handler->queue(LOK_CALLBACK_TEXT_SELECTION, "15, 25, 15, 10"); // 
Superseded.
@@ -1640,6 +1641,7 @@ void DesktopLOKTest::testTileInvalidationCompression()
     {
         std::vector<std::tuple<int, std::string>> notifs;
         std::unique_ptr<CallbackFlushHandler> handler(new 
CallbackFlushHandler(pDocument, callbackCompressionTest, &notifs));
+        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");
@@ -1660,6 +1662,7 @@ void DesktopLOKTest::testTileInvalidationCompression()
     {
         std::vector<std::tuple<int, std::string>> notifs;
         std::unique_ptr<CallbackFlushHandler> handler(new 
CallbackFlushHandler(pDocument, callbackCompressionTest, &notifs));
+        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
@@ -1683,6 +1686,7 @@ void DesktopLOKTest::testTileInvalidationCompression()
     {
         std::vector<std::tuple<int, std::string>> notifs;
         std::unique_ptr<CallbackFlushHandler> handler(new 
CallbackFlushHandler(pDocument, callbackCompressionTest, &notifs));
+        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
@@ -1709,6 +1713,7 @@ void DesktopLOKTest::testTileInvalidationCompression()
     {
         std::vector<std::tuple<int, std::string>> notifs;
         std::unique_ptr<CallbackFlushHandler> handler(new 
CallbackFlushHandler(pDocument, callbackCompressionTest, &notifs));
+        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
@@ -1744,6 +1749,7 @@ void DesktopLOKTest::testTileInvalidationCompression()
     {
         std::vector<std::tuple<int, std::string>> notifs;
         std::unique_ptr<CallbackFlushHandler> handler(new 
CallbackFlushHandler(pDocument, callbackCompressionTest, &notifs));
+        handler->setViewId(SfxLokHelper::getView());
 
         handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "0, 0, 239, 239, 0");
         handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "EMPTY, 0");
@@ -1768,6 +1774,7 @@ void DesktopLOKTest::testPartInInvalidation()
     {
         std::vector<std::tuple<int, std::string>> notifs;
         std::unique_ptr<CallbackFlushHandler> handler(new 
CallbackFlushHandler(pDocument, callbackCompressionTest, &notifs));
+        handler->setViewId(SfxLokHelper::getView());
 
         handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "10, 10, 20, 10");
         handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "20, 10, 20, 10");
@@ -1783,6 +1790,7 @@ void DesktopLOKTest::testPartInInvalidation()
     {
         std::vector<std::tuple<int, std::string>> notifs;
         std::unique_ptr<CallbackFlushHandler> handler(new 
CallbackFlushHandler(pDocument, callbackCompressionTest, &notifs));
+        handler->setViewId(SfxLokHelper::getView());
 
         handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "10, 10, 20, 10");
         handler->queue(LOK_CALLBACK_INVALIDATE_TILES, "40, 10, 20, 10");
@@ -1802,6 +1810,7 @@ void DesktopLOKTest::testPartInInvalidation()
 
         std::vector<std::tuple<int, std::string>> notifs;
         std::unique_ptr<CallbackFlushHandler> handler(new 
CallbackFlushHandler(pDocument, callbackCompressionTest, &notifs));
+        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");
@@ -1820,6 +1829,7 @@ void DesktopLOKTest::testPartInInvalidation()
 
         std::vector<std::tuple<int, std::string>> notifs;
         std::unique_ptr<CallbackFlushHandler> handler(new 
CallbackFlushHandler(pDocument, callbackCompressionTest, &notifs));
+        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");
@@ -1848,6 +1858,7 @@ void DesktopLOKTest::testBinaryCallback()
     {
         std::vector<std::tuple<int, std::string>> notifs;
         std::unique_ptr<CallbackFlushHandler> handler(new 
CallbackFlushHandler(pDocument, callbackBinaryCallbackTest, &notifs));
+        handler->setViewId(SfxLokHelper::getView());
 
         handler->queue(LOK_CALLBACK_INVALIDATE_TILES, rect1String.c_str());
 
@@ -1860,6 +1871,7 @@ void DesktopLOKTest::testBinaryCallback()
     {
         std::vector<std::tuple<int, std::string>> notifs;
         std::unique_ptr<CallbackFlushHandler> handler(new 
CallbackFlushHandler(pDocument, callbackBinaryCallbackTest, &notifs));
+        handler->setViewId(SfxLokHelper::getView());
 
         handler->libreOfficeKitViewInvalidateTilesCallback(&rect1, INT_MIN);
 
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index c38a6dd8d754..30bfd4594754 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -698,9 +698,17 @@ static bool lcl_isViewCallbackType(const int type)
     }
 }
 
-static bool isUpdatedType(int /*type*/)
+static bool isUpdatedType(int type)
 {
-    return false;
+    switch (type)
+    {
+        case LOK_CALLBACK_TEXT_SELECTION:
+        case LOK_CALLBACK_TEXT_SELECTION_START:
+        case LOK_CALLBACK_TEXT_SELECTION_END:
+            return true;
+        default:
+            return false;
+    }
 }
 
 static bool isUpdatedTypePerViewId(int type)
@@ -709,6 +717,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;
@@ -2121,31 +2130,53 @@ 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( const 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 << "]");
@@ -2155,13 +2186,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);
@@ -2178,6 +2209,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 c8b8b356f7e3..3c355e01800c 100644
--- a/sw/inc/viscrs.hxx
+++ b/sw/inc/viscrs.hxx
@@ -113,6 +113,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 2c77e6d4dd87..d28dab2c7d98 100644
--- a/sw/source/core/crsr/viscrs.cxx
+++ b/sw/source/core/crsr/viscrs.cxx
@@ -478,25 +478,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;
@@ -509,13 +498,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 c6d42d7830dd..d2e1731bbc91 100644
--- a/sw/source/uibase/uiview/viewsrch.cxx
+++ b/sw/source/uibase/uiview/viewsrch.cxx
@@ -126,8 +126,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 6a39b9064470..90ca5f2c9203 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;

Reply via email to