unoxml/inc/eventdispatcher.hxx           |    2 
 unoxml/source/dom/characterdata.cxx      |   26 +++++----
 unoxml/source/dom/characterdata.hxx      |    2 
 unoxml/source/dom/element.cxx            |   56 ++++++++++++--------
 unoxml/source/dom/node.cxx               |   85 +++++++++++++++++--------------
 unoxml/source/events/eventdispatcher.cxx |    5 +
 6 files changed, 102 insertions(+), 74 deletions(-)

New commits:
commit 004c882b698489f05b21513d2e54bc58f5ad49a4
Author:     Caolán McNamara <caolan.mcnam...@collabora.com>
AuthorDate: Mon Feb 24 10:21:52 2025 +0000
Commit:     Caolán McNamara <caolan.mcnam...@collabora.com>
CommitDate: Mon Feb 24 15:11:15 2025 +0100

    optimize unoxml for the common case of no listeners
    
    Change-Id: I64dcf61813c9a5dfa8a82fd0b39bad2bf916b9d2
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/182080
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>
    Tested-by: Jenkins

diff --git a/unoxml/inc/eventdispatcher.hxx b/unoxml/inc/eventdispatcher.hxx
index 9ecd42585d3c..f3c8f107a9a7 100644
--- a/unoxml/inc/eventdispatcher.hxx
+++ b/unoxml/inc/eventdispatcher.hxx
@@ -59,6 +59,8 @@ public:
         const css::uno::Reference<css::xml::dom::events::XEventListener>& 
aListener,
         bool bCapture);
 
+    bool hasListeners() const;
+
     static void callListeners(
         TypeListenerMap const& rTMap,
         xmlNodePtr const pNode,
diff --git a/unoxml/source/dom/characterdata.cxx 
b/unoxml/source/dom/characterdata.cxx
index 9e21aa03846c..b3c36318900e 100644
--- a/unoxml/source/dom/characterdata.cxx
+++ b/unoxml/source/dom/characterdata.cxx
@@ -18,6 +18,8 @@
  */
 
 #include "characterdata.hxx"
+#include "document.hxx"
+#include <eventdispatcher.hxx>
 
 #include <string.h>
 
@@ -43,9 +45,15 @@ namespace DOM
     {
     }
 
-    void CCharacterData::dispatchEvent_Impl(
+    void CCharacterData::dispatchEvent_Impl(::osl::ClearableMutexGuard& guard,
             OUString const& prevValue, OUString const& newValue)
     {
+        CDocument& rDocument(GetOwnerDocument());
+        if (!rDocument.GetEventDispatcher().hasListeners())
+            return;
+
+        guard.clear(); // release mutex before calling event handlers
+
         Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
         Reference< XMutationEvent > event(docevent->createEvent(
             u"DOMCharacterDataModified"_ustr), UNO_QUERY);
@@ -69,9 +77,7 @@ namespace DOM
             OUString oldValue(reinterpret_cast<char*>(m_aNodePtr->content), 
strlen(reinterpret_cast<char*>(m_aNodePtr->content)), RTL_TEXTENCODING_UTF8);
             xmlNodeAddContent(m_aNodePtr, reinterpret_cast<const 
xmlChar*>(OUStringToOString(arg, RTL_TEXTENCODING_UTF8).getStr()));
             OUString newValue(reinterpret_cast<char*>(m_aNodePtr->content), 
strlen(reinterpret_cast<char*>(m_aNodePtr->content)), RTL_TEXTENCODING_UTF8);
-
-            guard.clear(); // release mutex before calling event handlers
-            dispatchEvent_Impl(oldValue, newValue);
+            dispatchEvent_Impl(guard, oldValue, newValue);
         }
     }
 
@@ -103,8 +109,7 @@ namespace DOM
         xmlNodeSetContent(m_aNodePtr, reinterpret_cast<const 
xmlChar*>(OUStringToOString(tmp2, RTL_TEXTENCODING_UTF8).getStr()));
         OUString newValue(reinterpret_cast<char*>(m_aNodePtr->content), 
strlen(reinterpret_cast<char*>(m_aNodePtr->content)), RTL_TEXTENCODING_UTF8);
 
-        guard.clear(); // release mutex before calling event handlers
-        dispatchEvent_Impl(oldValue, newValue);
+        dispatchEvent_Impl(guard, oldValue, newValue);
 
     }
 
@@ -173,8 +178,7 @@ namespace DOM
         xmlNodeSetContent(m_aNodePtr, reinterpret_cast<const 
xmlChar*>(OUStringToOString(tmp2, RTL_TEXTENCODING_UTF8).getStr()));
         OUString newValue(reinterpret_cast<char*>(m_aNodePtr->content), 
strlen(reinterpret_cast<char*>(m_aNodePtr->content)), RTL_TEXTENCODING_UTF8);
 
-        guard.clear(); // release mutex before calling event handlers
-        dispatchEvent_Impl(oldValue, newValue);
+        dispatchEvent_Impl(guard, oldValue, newValue);
 
     }
 
@@ -210,8 +214,7 @@ namespace DOM
         xmlNodeSetContent(m_aNodePtr, reinterpret_cast<const 
xmlChar*>(OUStringToOString(tmp2, RTL_TEXTENCODING_UTF8).getStr()));
         OUString newValue(reinterpret_cast<char*>(m_aNodePtr->content), 
strlen(reinterpret_cast<char*>(m_aNodePtr->content)), RTL_TEXTENCODING_UTF8);
 
-        guard.clear(); // release mutex before calling event handlers
-        dispatchEvent_Impl(oldValue, newValue);
+        dispatchEvent_Impl(guard, oldValue, newValue);
 
     }
 
@@ -228,8 +231,7 @@ namespace DOM
             xmlNodeSetContent(m_aNodePtr, reinterpret_cast<const 
xmlChar*>(OUStringToOString(data, RTL_TEXTENCODING_UTF8).getStr()));
             OUString newValue(reinterpret_cast<char*>(m_aNodePtr->content), 
strlen(reinterpret_cast<char*>(m_aNodePtr->content)), RTL_TEXTENCODING_UTF8);
 
-            guard.clear(); // release mutex before calling event handlers
-            dispatchEvent_Impl(oldValue, newValue);
+            dispatchEvent_Impl(guard, oldValue, newValue);
         }
     }
 
diff --git a/unoxml/source/dom/characterdata.hxx 
b/unoxml/source/dom/characterdata.hxx
index 7728f65ef135..08cd089ae44d 100644
--- a/unoxml/source/dom/characterdata.hxx
+++ b/unoxml/source/dom/characterdata.hxx
@@ -44,7 +44,7 @@ namespace DOM
         CCharacterData(CDocument const& rDocument, ::osl::Mutex const& rMutex,
                 css::xml::dom::NodeType const& reNodeType, xmlNodePtr const& 
rpNode);
 
-        void dispatchEvent_Impl(
+        void dispatchEvent_Impl(::osl::ClearableMutexGuard& guard,
                 OUString const& prevValue, OUString const& newValue);
 
     public:
diff --git a/unoxml/source/dom/element.cxx b/unoxml/source/dom/element.cxx
index 1a59d85513f8..c131557bbc11 100644
--- a/unoxml/source/dom/element.cxx
+++ b/unoxml/source/dom/element.cxx
@@ -33,6 +33,7 @@
 #include <comphelper/attributelist.hxx>
 #include <comphelper/servicehelper.hxx>
 
+#include <eventdispatcher.hxx>
 #include <node.hxx>
 #include "attr.hxx"
 #include "elementlist.hxx"
@@ -622,18 +623,22 @@ namespace DOM
             xmlSetProp(m_aNodePtr, pName, pValue);
         }
 
-        // dispatch DOMAttrModified event
-        Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
-        Reference< XMutationEvent > event(docevent->createEvent(
-            u"DOMAttrModified"_ustr), UNO_QUERY);
-        event->initMutationEvent(u"DOMAttrModified"_ustr,
-            true, false,
-            getAttributeNode(name),
-            oldValue, value, name, aChangeType);
-
-        guard.clear(); // release mutex before calling event handlers
-        dispatchEvent(event);
-        dispatchSubtreeModified();
+        CDocument& rDocument(GetOwnerDocument());
+        if (rDocument.GetEventDispatcher().hasListeners())
+        {
+            // dispatch DOMAttrModified event
+            Reference< XDocumentEvent > docevent(getOwnerDocument(), 
UNO_QUERY);
+            Reference< XMutationEvent > event(docevent->createEvent(
+                u"DOMAttrModified"_ustr), UNO_QUERY);
+            event->initMutationEvent(u"DOMAttrModified"_ustr,
+                true, false,
+                getAttributeNode(name),
+                oldValue, value, name, aChangeType);
+
+            guard.clear(); // release mutex before calling event handlers
+            dispatchEvent(event);
+            dispatchSubtreeModified();
+        }
     }
 
     /**
@@ -703,18 +708,23 @@ namespace DOM
                         RTL_TEXTENCODING_UTF8);
             xmlSetNsProp(m_aNodePtr, pNs, pLName, pValue);
         }
-        // dispatch DOMAttrModified event
-        Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
-        Reference< XMutationEvent > event(docevent->createEvent(
-            u"DOMAttrModified"_ustr), UNO_QUERY);
-        event->initMutationEvent(
-            u"DOMAttrModified"_ustr, true, false,
-            getAttributeNodeNS(namespaceURI, OUString(reinterpret_cast<char 
const *>(pLName), strlen(reinterpret_cast<char const *>(pLName)), 
RTL_TEXTENCODING_UTF8)),
-            oldValue, value, qualifiedName, aChangeType);
 
-        guard.clear(); // release mutex before calling event handlers
-        dispatchEvent(event);
-        dispatchSubtreeModified();
+        CDocument& rDocument(GetOwnerDocument());
+        if (rDocument.GetEventDispatcher().hasListeners())
+        {
+            // dispatch DOMAttrModified event
+            Reference< XDocumentEvent > docevent(getOwnerDocument(), 
UNO_QUERY);
+            Reference< XMutationEvent > event(docevent->createEvent(
+                u"DOMAttrModified"_ustr), UNO_QUERY);
+            event->initMutationEvent(
+                u"DOMAttrModified"_ustr, true, false,
+                getAttributeNodeNS(namespaceURI, 
OUString(reinterpret_cast<char const *>(pLName), strlen(reinterpret_cast<char 
const *>(pLName)), RTL_TEXTENCODING_UTF8)),
+                oldValue, value, qualifiedName, aChangeType);
+
+            guard.clear(); // release mutex before calling event handlers
+            dispatchEvent(event);
+            dispatchSubtreeModified();
+        }
     }
 
     Reference< XNamedNodeMap > SAL_CALL
diff --git a/unoxml/source/dom/node.cxx b/unoxml/source/dom/node.cxx
index fdfabc5e21ce..b48a75ff8bde 100644
--- a/unoxml/source/dom/node.cxx
+++ b/unoxml/source/dom/node.cxx
@@ -357,27 +357,32 @@ namespace DOM
         // because that will not remove unneeded ns decls
         nscleanup(res, m_aNodePtr);
 
-        ::rtl::Reference<CNode> const pNode = GetOwnerDocument().GetCNode(res);
+        CDocument& rDocument(GetOwnerDocument());
+        ::rtl::Reference<CNode> const pNode = rDocument.GetCNode(res);
 
         if (!pNode.is()) { return nullptr; }
 
-        // dispatch DOMNodeInserted event, target is the new node
-        // this node is the related node
-        // does bubble
         pNode->m_bUnlinked = false; // will be deleted by xmlFreeDoc
-        Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
-        Reference< XMutationEvent > event(docevent->createEvent(
-            u"DOMNodeInserted"_ustr), UNO_QUERY);
-        event->initMutationEvent(u"DOMNodeInserted"_ustr, true, false, this,
-            OUString(), OUString(), OUString(), AttrChangeType(0) );
 
-        // the following dispatch functions use only UNO interfaces
-        // and call event listeners, so release mutex to prevent deadlocks.
-        guard.clear();
+        if (rDocument.GetEventDispatcher().hasListeners())
+        {
+            // dispatch DOMNodeInserted event, target is the new node
+            // this node is the related node
+            // does bubble
+            Reference< XDocumentEvent > docevent(getOwnerDocument(), 
UNO_QUERY);
+            Reference< XMutationEvent > event(docevent->createEvent(
+                u"DOMNodeInserted"_ustr), UNO_QUERY);
+            event->initMutationEvent(u"DOMNodeInserted"_ustr, true, false, 
this,
+                OUString(), OUString(), OUString(), AttrChangeType(0) );
+
+            // the following dispatch functions use only UNO interfaces
+            // and call event listeners, so release mutex to prevent deadlocks.
+            guard.clear();
 
-        dispatchEvent(event);
-        // dispatch subtree modified for this node
-        dispatchSubtreeModified();
+            dispatchEvent(event);
+            // dispatch subtree modified for this node
+            dispatchSubtreeModified();
+        }
 
         return pNode;
     }
@@ -752,30 +757,34 @@ namespace DOM
             pOld->m_bUnlinked = true;
         }
 
-        /*DOMNodeRemoved
-         * Fired when a node is being removed from its parent node.
-         * This event is dispatched before the node is removed from the tree.
-         * The target of this event is the node being removed.
-         *   Bubbles: Yes
-         *   Cancelable: No
-         *   Context Info: relatedNode holds the parent node
-         */
-        Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
-        Reference< XMutationEvent > event(docevent->createEvent(
-            u"DOMNodeRemoved"_ustr), UNO_QUERY);
-        event->initMutationEvent(u"DOMNodeRemoved"_ustr,
-            true,
-            false,
-            this,
-            OUString(), OUString(), OUString(), AttrChangeType(0) );
-
-        // the following dispatch functions use only UNO interfaces
-        // and call event listeners, so release mutex to prevent deadlocks.
-        guard.clear();
+        CDocument& rDocument(GetOwnerDocument());
+        if (rDocument.GetEventDispatcher().hasListeners())
+        {
+            /*DOMNodeRemoved
+             * Fired when a node is being removed from its parent node.
+             * This event is dispatched before the node is removed from the 
tree.
+             * The target of this event is the node being removed.
+             *   Bubbles: Yes
+             *   Cancelable: No
+             *   Context Info: relatedNode holds the parent node
+             */
+            Reference< XDocumentEvent > docevent(getOwnerDocument(), 
UNO_QUERY);
+            Reference< XMutationEvent > event(docevent->createEvent(
+                u"DOMNodeRemoved"_ustr), UNO_QUERY);
+            event->initMutationEvent(u"DOMNodeRemoved"_ustr,
+                true,
+                false,
+                this,
+                OUString(), OUString(), OUString(), AttrChangeType(0) );
+
+            // the following dispatch functions use only UNO interfaces
+            // and call event listeners, so release mutex to prevent deadlocks.
+            guard.clear();
 
-        dispatchEvent(event);
-        // subtree modified for this node
-        dispatchSubtreeModified();
+            dispatchEvent(event);
+            // subtree modified for this node
+            dispatchSubtreeModified();
+        }
 
         return xReturn;
     }
diff --git a/unoxml/source/events/eventdispatcher.cxx 
b/unoxml/source/events/eventdispatcher.cxx
index 201f682f7d66..289962f97855 100644
--- a/unoxml/source/events/eventdispatcher.cxx
+++ b/unoxml/source/events/eventdispatcher.cxx
@@ -78,6 +78,11 @@ namespace DOM::events {
         }
     }
 
+    bool CEventDispatcher::hasListeners() const
+    {
+        return !m_CaptureListeners.empty() || !m_TargetListeners.empty();
+    }
+
     CEventDispatcher::~CEventDispatcher()
     {
     }

Reply via email to