[Libreoffice-commits] core.git: vcl/inc vcl/source

Noel Grandin noel at peralex.com
Fri Dec 18 00:53:51 PST 2015


 vcl/inc/window.h            |    3 +++
 vcl/source/window/event.cxx |   22 +++++++++++++++++-----
 2 files changed, 20 insertions(+), 5 deletions(-)

New commits:
commit 60e67b387e79185a33eb07bc03b01cd6d0d0a56b
Author: Noel Grandin <noel at peralex.com>
Date:   Fri Dec 18 10:08:35 2015 +0200

    fix O(n^2) in vcl event broadcasting tdf#90199
    
    Change-Id: If3d7514364589058334369432cdcf4f7586c239d

diff --git a/vcl/inc/window.h b/vcl/inc/window.h
index 5d792de..e950369 100644
--- a/vcl/inc/window.h
+++ b/vcl/inc/window.h
@@ -39,6 +39,7 @@
 #include <vcl/rendersettings.hxx>
 #include "vcleventlisteners.hxx"
 #include <vector>
+#include <set>
 
 struct SalPaintEvent;
 struct ImplDelData;
@@ -231,6 +232,8 @@ public:
     VclPtr<vcl::Window> mpDlgCtrlDownWindow;
     std::vector<Link<VclWindowEvent&,void>> maEventListeners;
     std::vector<Link<VclWindowEvent&,void>> maChildEventListeners;
+    int maChildEventListenersIteratingCount;
+    std::set<Link<VclWindowEvent&,void>> maChildEventListenersDeleted;
 
     // The canvas interface for this VCL window. Is persistent after the first GetCanvas() call
     css::uno::WeakReference< css::rendering::XCanvas >    mxCanvas;
diff --git a/vcl/source/window/event.cxx b/vcl/source/window/event.cxx
index f90ac28..c001c7e 100644
--- a/vcl/source/window/event.cxx
+++ b/vcl/source/window/event.cxx
@@ -30,6 +30,7 @@
 #include <com/sun/star/awt/MouseEvent.hpp>
 #include <com/sun/star/awt/KeyModifier.hpp>
 #include <com/sun/star/awt/MouseButton.hpp>
+#include <comphelper/scopeguard.hxx>
 
 namespace vcl {
 
@@ -238,17 +239,26 @@ void Window::CallEventListeners( sal_uLong nEvent, void* pData )
         if ( aDelData.IsDead() )
             return;
 
-        auto& rChildListeners = pWindow->mpWindowImpl->maChildEventListeners;
-        if (!rChildListeners.empty())
+        auto& rWindowImpl = *pWindow->mpWindowImpl;
+        if (!rWindowImpl.maChildEventListeners.empty())
         {
             // Copy the list, because this can be destroyed when calling a Link...
-            std::vector<Link<VclWindowEvent&,void>> aCopy( rChildListeners );
+            std::vector<Link<VclWindowEvent&,void>> aCopy( rWindowImpl.maChildEventListeners );
+            // we use an iterating counter/flag and a set of deleted Link's to avoid O(n^2) behaviour
+            rWindowImpl.maChildEventListenersIteratingCount++;
+            comphelper::ScopeGuard aGuard(
+                [&rWindowImpl]()
+                {
+                    if (--rWindowImpl.maChildEventListenersIteratingCount == 0)
+                    rWindowImpl.maChildEventListenersDeleted.clear();
+                }
+            );
             for ( Link<VclWindowEvent&,void>& rLink : aCopy )
             {
                 if (aDelData.IsDead())
                     return;
-                // check this hasn't been removed in some re-enterancy scenario fdo#47368
-                if( std::find(rChildListeners.begin(), rChildListeners.end(), rLink) != rChildListeners.end() )
+                // Check this hasn't been removed in some re-enterancy scenario fdo#47368.
+                if( rWindowImpl.maChildEventListenersDeleted.find(rLink) != rWindowImpl.maChildEventListenersDeleted.end() )
                     rLink.Call( aEvent );
             }
         }
@@ -292,6 +302,8 @@ void Window::RemoveChildEventListener( const Link<VclWindowEvent&,void>& rEventL
     {
         auto& rListeners = mpWindowImpl->maChildEventListeners;
         rListeners.erase( std::remove(rListeners.begin(), rListeners.end(), rEventListener ), rListeners.end() );
+        if (mpWindowImpl->maChildEventListenersIteratingCount)
+            mpWindowImpl->maChildEventListenersDeleted.insert(rEventListener);
     }
 }
 


More information about the Libreoffice-commits mailing list