Dispatch pending events only for current page
authordougk@apple.com <dougk@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 21 May 2020 16:04:12 +0000 (16:04 +0000)
committerdougk@apple.com <dougk@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 21 May 2020 16:04:12 +0000 (16:04 +0000)
https://bugs.webkit.org/show_bug.cgi?id=211975
<rdar://problem/58942759>

Reviewed by Chris Dumez.

Document::implicitClose() should not dispatch events globally. The EventSender class operates as a singleton pattern
for each event queue, so to add some means to restrict which documents are handling events, we can send the current
page pointer and only dispatch the event if the event is for the same page. Other events are simply re-enqueued
to be triggered at a later time.

* dom/Document.cpp:
(WebCore::Document::implicitClose):
* dom/EventSender.h:
(WebCore::EventSender::timerFired):
(WebCore::EventSender<T>::dispatchPendingEvents):
* html/HTMLLinkElement.cpp:
(WebCore::HTMLLinkElement::dispatchPendingLoadEvents):
* html/HTMLLinkElement.h:
* html/HTMLStyleElement.cpp:
(WebCore::HTMLStyleElement::dispatchPendingLoadEvents):
* html/HTMLStyleElement.h:
* loader/ImageLoader.cpp:
(WebCore::ImageLoader::dispatchPendingBeforeLoadEvents):
(WebCore::ImageLoader::dispatchPendingLoadEvents):
(WebCore::ImageLoader::dispatchPendingErrorEvents):
* loader/ImageLoader.h:
(WebCore::ImageLoader::document):
* xml/parser/XMLDocumentParser.cpp:
(WebCore::XMLDocumentParser::append):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@262003 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/dom/Document.cpp
Source/WebCore/dom/EventSender.h
Source/WebCore/html/HTMLLinkElement.cpp
Source/WebCore/html/HTMLLinkElement.h
Source/WebCore/html/HTMLStyleElement.cpp
Source/WebCore/html/HTMLStyleElement.h
Source/WebCore/loader/ImageLoader.cpp
Source/WebCore/loader/ImageLoader.h
Source/WebCore/xml/parser/XMLDocumentParser.cpp

index ee32b9f..7844b89 100644 (file)
@@ -1,3 +1,36 @@
+2020-05-21  Doug Kelly  <dougk@apple.com>
+
+        Dispatch pending events only for current page
+        https://bugs.webkit.org/show_bug.cgi?id=211975
+        <rdar://problem/58942759>
+
+        Reviewed by Chris Dumez.
+
+        Document::implicitClose() should not dispatch events globally. The EventSender class operates as a singleton pattern
+        for each event queue, so to add some means to restrict which documents are handling events, we can send the current
+        page pointer and only dispatch the event if the event is for the same page. Other events are simply re-enqueued
+        to be triggered at a later time.
+
+        * dom/Document.cpp:
+        (WebCore::Document::implicitClose):
+        * dom/EventSender.h:
+        (WebCore::EventSender::timerFired):
+        (WebCore::EventSender<T>::dispatchPendingEvents):
+        * html/HTMLLinkElement.cpp:
+        (WebCore::HTMLLinkElement::dispatchPendingLoadEvents):
+        * html/HTMLLinkElement.h:
+        * html/HTMLStyleElement.cpp:
+        (WebCore::HTMLStyleElement::dispatchPendingLoadEvents):
+        * html/HTMLStyleElement.h:
+        * loader/ImageLoader.cpp:
+        (WebCore::ImageLoader::dispatchPendingBeforeLoadEvents):
+        (WebCore::ImageLoader::dispatchPendingLoadEvents):
+        (WebCore::ImageLoader::dispatchPendingErrorEvents):
+        * loader/ImageLoader.h:
+        (WebCore::ImageLoader::document):
+        * xml/parser/XMLDocumentParser.cpp:
+        (WebCore::XMLDocumentParser::append):
+
 2020-05-21  Simon Fraser  <simon.fraser@apple.com>
 
         [macOS] Scrolling synchronization part 2: Have the scrolling thread detect when the main thread is slow to respond to start a rendering update
index cb38db2..513b828 100644 (file)
@@ -3046,11 +3046,13 @@ void Document::implicitClose()
         // FIXME: We shouldn't be dispatching pending events globally on all Documents here.
         // For now, only do this when there is a Frame, otherwise this could cause JS reentrancy
         // below SVG font parsing, for example. <https://webkit.org/b/136269>
-        ImageLoader::dispatchPendingBeforeLoadEvents();
-        ImageLoader::dispatchPendingLoadEvents();
-        ImageLoader::dispatchPendingErrorEvents();
-        HTMLLinkElement::dispatchPendingLoadEvents();
-        HTMLStyleElement::dispatchPendingLoadEvents();
+        if (auto* currentPage = page()) {
+            ImageLoader::dispatchPendingBeforeLoadEvents(currentPage);
+            ImageLoader::dispatchPendingLoadEvents(currentPage);
+            ImageLoader::dispatchPendingErrorEvents(currentPage);
+            HTMLLinkElement::dispatchPendingLoadEvents(currentPage);
+            HTMLStyleElement::dispatchPendingLoadEvents(currentPage);
+        }
 
         if (svgExtensions())
             accessSVGExtensions().dispatchLoadEventToOutermostSVGElements();
index 5efd7a8..0d930e4 100644 (file)
@@ -30,6 +30,8 @@
 
 namespace WebCore {
 
+class Page;
+
 template<typename T> class EventSender {
     WTF_MAKE_NONCOPYABLE(EventSender); WTF_MAKE_FAST_ALLOCATED;
 public:
@@ -38,7 +40,7 @@ public:
     const AtomString& eventType() const { return m_eventType; }
     void dispatchEventSoon(T&);
     void cancelEvent(T&);
-    void dispatchPendingEvents();
+    void dispatchPendingEvents(Page*);
 
 #if ASSERT_ENABLED
     bool hasPendingEvents(T& sender) const
@@ -48,7 +50,7 @@ public:
 #endif
 
 private:
-    void timerFired() { dispatchPendingEvents(); }
+    void timerFired() { dispatchPendingEvents(nullptr); }
 
     AtomString m_eventType;
     Timer m_timer;
@@ -83,7 +85,7 @@ template<typename T> void EventSender<T>::cancelEvent(T& sender)
     }
 }
 
-template<typename T> void EventSender<T>::dispatchPendingEvents()
+template<typename T> void EventSender<T>::dispatchPendingEvents(Page* page)
 {
     // Need to avoid re-entering this function; if new dispatches are
     // scheduled before the parent finishes processing the list, they
@@ -99,7 +101,10 @@ template<typename T> void EventSender<T>::dispatchPendingEvents()
     for (auto& event : m_dispatchingList) {
         if (T* sender = event) {
             event = nullptr;
-            sender->dispatchPendingEvent(this);
+            if (!page || sender->document().page() == page)
+                sender->dispatchPendingEvent(this);
+            else
+                dispatchEventSoon(*sender);
         }
     }
     m_dispatchingList.clear();
index 2b9daaa..0abacaa 100644 (file)
@@ -524,9 +524,9 @@ bool HTMLLinkElement::sheetLoaded()
     return false;
 }
 
-void HTMLLinkElement::dispatchPendingLoadEvents()
+void HTMLLinkElement::dispatchPendingLoadEvents(Page* page)
 {
-    linkLoadEventSender().dispatchPendingEvents();
+    linkLoadEventSender().dispatchPendingEvents(page);
 }
 
 void HTMLLinkElement::dispatchPendingEvent(LinkEventSender* eventSender)
index 5a9ce0b..87dff4d 100644 (file)
@@ -36,6 +36,7 @@ namespace WebCore {
 
 class DOMTokenList;
 class HTMLLinkElement;
+class Page;
 struct MediaQueryParserContext;
 
 template<typename T> class EventSender;
@@ -70,7 +71,7 @@ public:
     WEBCORE_EXPORT String as() const;
 
     void dispatchPendingEvent(LinkEventSender*);
-    static void dispatchPendingLoadEvents();
+    static void dispatchPendingLoadEvents(Page*);
 
     WEBCORE_EXPORT DOMTokenList& relList();
 
index edae2ed..3add229 100644 (file)
@@ -120,9 +120,9 @@ void HTMLStyleElement::childrenChanged(const ChildChange& change)
     m_styleSheetOwner.childrenChanged(*this);
 }
 
-void HTMLStyleElement::dispatchPendingLoadEvents()
+void HTMLStyleElement::dispatchPendingLoadEvents(Page* page)
 {
-    styleLoadEventSender().dispatchPendingEvents();
+    styleLoadEventSender().dispatchPendingEvents(page);
 }
 
 void HTMLStyleElement::dispatchPendingEvent(StyleEventSender* eventSender)
index a553ea3..2dae917 100644 (file)
@@ -28,6 +28,7 @@
 namespace WebCore {
 
 class HTMLStyleElement;
+class Page;
 class StyleSheet;
 
 template<typename T> class EventSender;
@@ -47,7 +48,7 @@ public:
     WEBCORE_EXPORT void setDisabled(bool);
 
     void dispatchPendingEvent(StyleEventSender*);
-    static void dispatchPendingLoadEvents();
+    static void dispatchPendingLoadEvents(Page*);
 
     void finishParsingChildren() final;
 
index 75d5fe0..6711f87 100644 (file)
@@ -559,19 +559,19 @@ void ImageLoader::dispatchPendingErrorEvent()
     updatedHasPendingEvent();
 }
 
-void ImageLoader::dispatchPendingBeforeLoadEvents()
+void ImageLoader::dispatchPendingBeforeLoadEvents(Page* page)
 {
-    beforeLoadEventSender().dispatchPendingEvents();
+    beforeLoadEventSender().dispatchPendingEvents(page);
 }
 
-void ImageLoader::dispatchPendingLoadEvents()
+void ImageLoader::dispatchPendingLoadEvents(Page* page)
 {
-    loadEventSender().dispatchPendingEvents();
+    loadEventSender().dispatchPendingEvents(page);
 }
 
-void ImageLoader::dispatchPendingErrorEvents()
+void ImageLoader::dispatchPendingErrorEvents(Page* page)
 {
-    errorEventSender().dispatchPendingEvents();
+    errorEventSender().dispatchPendingEvents(page);
 }
 
 void ImageLoader::elementDidMoveToNewDocument(Document& oldDocument)
index 2ec0f15..b8423c7 100644 (file)
@@ -34,6 +34,7 @@ class DeferredPromise;
 class Document;
 class Element;
 class ImageLoader;
+class Page;
 class RenderImageResource;
 
 template<typename T> class EventSender;
@@ -72,14 +73,16 @@ public:
 
     void dispatchPendingEvent(ImageEventSender*);
 
-    static void dispatchPendingBeforeLoadEvents();
-    static void dispatchPendingLoadEvents();
-    static void dispatchPendingErrorEvents();
+    static void dispatchPendingBeforeLoadEvents(Page*);
+    static void dispatchPendingLoadEvents(Page*);
+    static void dispatchPendingErrorEvents(Page*);
 
     void loadDeferredImage();
 
     bool isDeferred() const { return m_lazyImageLoadState == LazyImageLoadState::Deferred; }
 
+    Document& document() { return m_element.document(); }
+
 protected:
     explicit ImageLoader(Element&);
     void notifyFinished(CachedResource&, const NetworkLoadMetrics&) override;
index f4effec..8173c74 100644 (file)
@@ -125,7 +125,7 @@ void XMLDocumentParser::append(RefPtr<StringImpl>&& inputSource)
     doWrite(source);
 
     // After parsing, dispatch image beforeload events.
-    ImageLoader::dispatchPendingBeforeLoadEvents();
+    ImageLoader::dispatchPendingBeforeLoadEvents(nullptr);
 }
 
 void XMLDocumentParser::handleError(XMLErrors::ErrorType type, const char* m, TextPosition position)