Diff
Modified: trunk/Source/WebCore/ChangeLog (290294 => 290295)
--- trunk/Source/WebCore/ChangeLog 2022-02-22 09:42:11 UTC (rev 290294)
+++ trunk/Source/WebCore/ChangeLog 2022-02-22 09:47:45 UTC (rev 290295)
@@ -1,3 +1,45 @@
+2022-02-22 Chris Dumez <[email protected]>
+
+ Avoid having to iterate the whole frame tree(s) every time we need to dispatch storage events
+ https://bugs.webkit.org/show_bug.cgi?id=236985
+
+ Reviewed by Darin Adler.
+
+ Avoid having to iterate the whole frame tree(s) every time we need to dispatch storage events,
+ by keeping track of window objects interested in storage events. A Window object is interested
+ in storage events if both of the following conditions is true:
+ 1. It has a Storage object (either localStorage or sessionStorage)
+ 2. It has a storage event listener registered.
+
+ This patch also refactors the code so that we share more logic between WebKit1 and WebKit2.
+
+ * inspector/agents/InspectorDOMStorageAgent.cpp:
+ (WebCore::InspectorDOMStorageAgent::setDOMStorageItem):
+ (WebCore::InspectorDOMStorageAgent::removeDOMStorageItem):
+ (WebCore::InspectorDOMStorageAgent::clearDOMStorageItems):
+ * loader/EmptyClients.cpp:
+ * page/DOMWindow.cpp:
+ (WebCore::windowsInterestedInStorageEvents):
+ (WebCore::DOMWindow::forEachWindowInterestedInStorageEvents):
+ (WebCore::DOMWindow::~DOMWindow):
+ (WebCore::DOMWindow::willDetachDocumentFromFrame):
+ (WebCore::DOMWindow::eventListenersDidChange):
+ * page/DOMWindow.h:
+ * page/DOMWindowProperty.h:
+ * storage/Storage.cpp:
+ (WebCore::Storage::setItem):
+ (WebCore::Storage::removeItem):
+ (WebCore::Storage::clear):
+ * storage/StorageArea.h:
+ * storage/StorageEventDispatcher.cpp:
+ (WebCore::dispatchSessionStorageEventsToWindows):
+ (WebCore::dispatchLocalStorageEventsToWindows):
+ (WebCore::StorageEventDispatcher::dispatchSessionStorageEvents):
+ (WebCore::StorageEventDispatcher::dispatchLocalStorageEvents):
+ (WebCore::StorageEventDispatcher::dispatchSessionStorageEventsToFrames): Deleted.
+ (WebCore::StorageEventDispatcher::dispatchLocalStorageEventsToFrames): Deleted.
+ * storage/StorageEventDispatcher.h:
+
2022-02-21 Alex Christensen <[email protected]>
Improve const correctness for SecurityOrigin accessors
Modified: trunk/Source/WebCore/inspector/agents/InspectorDOMStorageAgent.cpp (290294 => 290295)
--- trunk/Source/WebCore/inspector/agents/InspectorDOMStorageAgent.cpp 2022-02-22 09:42:11 UTC (rev 290294)
+++ trunk/Source/WebCore/inspector/agents/InspectorDOMStorageAgent.cpp 2022-02-22 09:47:45 UTC (rev 290295)
@@ -125,7 +125,7 @@
return makeUnexpected(errorString);
bool quotaException = false;
- storageArea->setItem(frame, key, value, quotaException);
+ storageArea->setItem(*frame, key, value, quotaException);
if (quotaException)
return makeUnexpected(DOMException::name(QuotaExceededError));
@@ -141,7 +141,7 @@
if (!storageArea)
return makeUnexpected(errorString);
- storageArea->removeItem(frame, key);
+ storageArea->removeItem(*frame, key);
return { };
}
@@ -155,7 +155,7 @@
if (!storageArea)
return makeUnexpected(errorString);
- storageArea->clear(frame);
+ storageArea->clear(*frame);
return { };
}
Modified: trunk/Source/WebCore/loader/EmptyClients.cpp (290294 => 290295)
--- trunk/Source/WebCore/loader/EmptyClients.cpp 2022-02-22 09:42:11 UTC (rev 290294)
+++ trunk/Source/WebCore/loader/EmptyClients.cpp 2022-02-22 09:47:45 UTC (rev 290295)
@@ -484,9 +484,9 @@
unsigned length() final { return 0; }
String key(unsigned) final { return { }; }
String item(const String&) final { return { }; }
- void setItem(Frame*, const String&, const String&, bool&) final { }
- void removeItem(Frame*, const String&) final { }
- void clear(Frame*) final { }
+ void setItem(Frame&, const String&, const String&, bool&) final { }
+ void removeItem(Frame&, const String&) final { }
+ void clear(Frame&) final { }
bool contains(const String&) final { return false; }
StorageType storageType() const final { return StorageType::Local; }
size_t memoryBytesUsedByCache() final { return 0; }
Modified: trunk/Source/WebCore/page/DOMWindow.cpp (290294 => 290295)
--- trunk/Source/WebCore/page/DOMWindow.cpp 2022-02-22 09:42:11 UTC (rev 290294)
+++ trunk/Source/WebCore/page/DOMWindow.cpp 2022-02-22 09:47:45 UTC (rev 290295)
@@ -156,6 +156,18 @@
static const Seconds defaultTransientActivationDuration { 2_s };
+static WeakHashSet<DOMWindow>& windowsInterestedInStorageEvents()
+{
+ static MainThreadNeverDestroyed<WeakHashSet<DOMWindow>> set;
+ return set;
+}
+
+void DOMWindow::forEachWindowInterestedInStorageEvents(const Function<void(DOMWindow&)>& apply)
+{
+ for (auto& window : copyToVectorOf<Ref<DOMWindow>>(windowsInterestedInStorageEvents()))
+ apply(window);
+}
+
static std::optional<Seconds>& transientActivationDurationOverrideForTesting()
{
static NeverDestroyed<std::optional<Seconds>> overrideForTesting;
@@ -442,6 +454,8 @@
#endif
removeLanguageChangeObserver(this);
+
+ windowsInterestedInStorageEvents().remove(*this);
}
RefPtr<MediaQueryList> DOMWindow::matchMedia(const String& media)
@@ -499,6 +513,8 @@
if (m_performance)
m_performance->clearResourceTimings();
+ windowsInterestedInStorageEvents().remove(*this);
+
JSDOMWindowBase::fireFrameClearedWatchpointsForWindow(this);
InspectorInstrumentation::frameWindowDiscarded(*frame(), this);
}
@@ -832,6 +848,8 @@
auto storageArea = page->sessionStorage()->storageArea(document->securityOrigin());
m_sessionStorage = Storage::create(*this, WTFMove(storageArea));
+ if (hasEventListeners(eventNames().storageEvent))
+ windowsInterestedInStorageEvents().add(*this);
return m_sessionStorage.get();
}
@@ -866,6 +884,8 @@
auto storageArea = page->storageNamespaceProvider().localStorageArea(*document);
m_localStorage = Storage::create(*this, WTFMove(storageArea));
+ if (hasEventListeners(eventNames().storageEvent))
+ windowsInterestedInStorageEvents().add(*this);
return m_localStorage.get();
}
@@ -2697,4 +2717,14 @@
return document ? document->frame() : nullptr;
}
+void DOMWindow::eventListenersDidChange()
+{
+ if (m_localStorage || m_sessionStorage) {
+ if (hasEventListeners(eventNames().storageEvent))
+ windowsInterestedInStorageEvents().add(*this);
+ else
+ windowsInterestedInStorageEvents().remove(*this);
+ }
+}
+
} // namespace WebCore
Modified: trunk/Source/WebCore/page/DOMWindow.h (290294 => 290295)
--- trunk/Source/WebCore/page/DOMWindow.h 2022-02-22 09:42:11 UTC (rev 290294)
+++ trunk/Source/WebCore/page/DOMWindow.h 2022-02-22 09:47:45 UTC (rev 290295)
@@ -410,6 +410,9 @@
void setMayReuseForNavigation(bool mayReuseForNavigation) { m_mayReuseForNavigation = mayReuseForNavigation; }
bool mayReuseForNavigation() const { return m_mayReuseForNavigation; }
+ Page* page() const;
+ WEBCORE_EXPORT static void forEachWindowInterestedInStorageEvents(const Function<void(DOMWindow&)>&);
+
private:
explicit DOMWindow(Document&);
@@ -417,8 +420,8 @@
bool isLocalDOMWindow() const final { return true; }
bool isRemoteDOMWindow() const final { return false; }
+ void eventListenersDidChange() final;
- Page* page() const;
bool allowedToChangeWindowGeometry() const;
static ExceptionOr<RefPtr<Frame>> createWindow(const String& urlString, const AtomString& frameName, const WindowFeatures&, DOMWindow& activeWindow, Frame& firstFrame, Frame& openerFrame, const Function<void(DOMWindow&)>& prepareDialogFunction = nullptr);
Modified: trunk/Source/WebCore/page/DOMWindowProperty.h (290294 => 290295)
--- trunk/Source/WebCore/page/DOMWindowProperty.h 2022-02-22 09:42:11 UTC (rev 290294)
+++ trunk/Source/WebCore/page/DOMWindowProperty.h 2022-02-22 09:47:45 UTC (rev 290295)
@@ -34,7 +34,7 @@
class DOMWindowProperty {
public:
- Frame* frame() const;
+ WEBCORE_EXPORT Frame* frame() const;
DOMWindow* window() const;
protected:
Modified: trunk/Source/WebCore/storage/Storage.cpp (290294 => 290295)
--- trunk/Source/WebCore/storage/Storage.cpp 2022-02-22 09:42:11 UTC (rev 290294)
+++ trunk/Source/WebCore/storage/Storage.cpp 2022-02-22 09:47:45 UTC (rev 290295)
@@ -81,7 +81,7 @@
return Exception { InvalidAccessError };
bool quotaException = false;
- m_storageArea->setItem(frame, key, value, quotaException);
+ m_storageArea->setItem(*frame, key, value, quotaException);
if (quotaException)
return Exception { QuotaExceededError };
return { };
@@ -93,7 +93,7 @@
if (!frame)
return Exception { InvalidAccessError };
- m_storageArea->removeItem(frame, key);
+ m_storageArea->removeItem(*frame, key);
return { };
}
@@ -103,7 +103,7 @@
if (!frame)
return Exception { InvalidAccessError };
- m_storageArea->clear(frame);
+ m_storageArea->clear(*frame);
return { };
}
Modified: trunk/Source/WebCore/storage/StorageArea.h (290294 => 290295)
--- trunk/Source/WebCore/storage/StorageArea.h 2022-02-22 09:42:11 UTC (rev 290294)
+++ trunk/Source/WebCore/storage/StorageArea.h 2022-02-22 09:47:45 UTC (rev 290295)
@@ -46,9 +46,9 @@
virtual unsigned length() = 0;
virtual String key(unsigned index) = 0;
virtual String item(const String& key) = 0;
- virtual void setItem(Frame* sourceFrame, const String& key, const String& value, bool& quotaException) = 0;
- virtual void removeItem(Frame* sourceFrame, const String& key) = 0;
- virtual void clear(Frame* sourceFrame) = 0;
+ virtual void setItem(Frame& sourceFrame, const String& key, const String& value, bool& quotaException) = 0;
+ virtual void removeItem(Frame& sourceFrame, const String& key) = 0;
+ virtual void clear(Frame& sourceFrame) = 0;
virtual bool contains(const String& key) = 0;
virtual StorageType storageType() const = 0;
Modified: trunk/Source/WebCore/storage/StorageEventDispatcher.cpp (290294 => 290295)
--- trunk/Source/WebCore/storage/StorageEventDispatcher.cpp 2022-02-22 09:42:11 UTC (rev 290294)
+++ trunk/Source/WebCore/storage/StorageEventDispatcher.cpp 2022-02-22 09:47:45 UTC (rev 290295)
@@ -40,69 +40,68 @@
namespace WebCore {
-void StorageEventDispatcher::dispatchSessionStorageEvents(const String& key, const String& oldValue, const String& newValue, const SecurityOrigin& securityOrigin, Frame* sourceFrame)
+static void dispatchSessionStorageEventsToWindows(Page& page, const Vector<Ref<DOMWindow>>& windows, const String& key, const String& oldValue, const String& newValue, const String& url, const SecurityOrigin& securityOrigin)
{
- Page* page = sourceFrame->page();
- if (!page)
- return;
+ InspectorInstrumentation::didDispatchDOMStorageEvent(page, key, oldValue, newValue, StorageType::Session, securityOrigin);
- Vector<Ref<Frame>> frames;
-
- // Send events only to our page.
- for (Frame* frame = &page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
- if (auto* window = frame->window(); !window || !window->hasEventListeners(eventNames().storageEvent))
- continue;
- if (sourceFrame != frame && frame->document()->securityOrigin().equal(&securityOrigin))
- frames.append(*frame);
+ for (auto& window : windows) {
+ RefPtr document = window->document();
+ auto result = window->sessionStorage();
+ if (!result.hasException()) // https://html.spec.whatwg.org/multipage/webstorage.html#the-storage-event:event-storage
+ document->queueTaskToDispatchEventOnWindow(TaskSource::DOMManipulation, StorageEvent::create(eventNames().storageEvent, key, oldValue, newValue, url, result.releaseReturnValue()));
}
-
- dispatchSessionStorageEventsToFrames(*page, frames, key, oldValue, newValue, sourceFrame->document()->url().string(), securityOrigin);
}
-void StorageEventDispatcher::dispatchLocalStorageEvents(const String& key, const String& oldValue, const String& newValue, const SecurityOrigin& securityOrigin, Frame* sourceFrame)
+static void dispatchLocalStorageEventsToWindows(PageGroup& pageGroup, const Vector<Ref<DOMWindow>>& windows, const String& key, const String& oldValue, const String& newValue, const String& url, const SecurityOrigin& securityOrigin)
{
- Page* page = sourceFrame->page();
- if (!page)
- return;
+ for (auto& page : pageGroup.pages())
+ InspectorInstrumentation::didDispatchDOMStorageEvent(page, key, oldValue, newValue, StorageType::Local, securityOrigin);
- Vector<Ref<Frame>> frames;
-
- // Send events to every page.
- for (auto& pageInGroup : page->group().pages()) {
- for (auto* frame = &pageInGroup.mainFrame(); frame; frame = frame->tree().traverseNext()) {
- if (auto* window = frame->window(); !window || !window->hasEventListeners(eventNames().storageEvent))
- continue;
- if (sourceFrame != frame && frame->document()->securityOrigin().equal(&securityOrigin))
- frames.append(*frame);
- }
+ for (auto& window : windows) {
+ RefPtr document = window->document();
+ auto result = window->localStorage();
+ if (!result.hasException()) // https://html.spec.whatwg.org/multipage/webstorage.html#the-storage-event:event-storage
+ document->queueTaskToDispatchEventOnWindow(TaskSource::DOMManipulation, StorageEvent::create(eventNames().storageEvent, key, oldValue, newValue, url, result.releaseReturnValue()));
}
-
- dispatchLocalStorageEventsToFrames(page->group(), frames, key, oldValue, newValue, sourceFrame->document()->url().string(), securityOrigin);
}
-void StorageEventDispatcher::dispatchSessionStorageEventsToFrames(Page& page, const Vector<Ref<Frame>>& frames, const String& key, const String& oldValue, const String& newValue, const String& url, const SecurityOrigin& securityOrigin)
+void StorageEventDispatcher::dispatchSessionStorageEvents(const String& key, const String& oldValue, const String& newValue, Page& page, const SecurityOrigin& securityOrigin, const String& url, const Function<bool(Storage&)>& isSourceStorage)
{
- InspectorInstrumentation::didDispatchDOMStorageEvent(page, key, oldValue, newValue, StorageType::Session, securityOrigin);
+ Vector<Ref<DOMWindow>> windows;
+ DOMWindow::forEachWindowInterestedInStorageEvents([&](auto& window) {
+ if (!window.optionalSessionStorage())
+ return;
+ // Send events only to our page.
+ if (window.page() != &page)
+ return;
+ if (isSourceStorage(*window.optionalSessionStorage()))
+ return;
+ if (!securityOrigin.equal(window.securityOrigin()))
+ return;
+ windows.append(window);
+ });
- for (auto& frame : frames) {
- RefPtr document = frame->document();
- auto result = document->domWindow()->sessionStorage();
- if (!result.hasException()) // https://html.spec.whatwg.org/multipage/webstorage.html#the-storage-event:event-storage
- document->queueTaskToDispatchEventOnWindow(TaskSource::DOMManipulation, StorageEvent::create(eventNames().storageEvent, key, oldValue, newValue, url, result.releaseReturnValue()));
- }
+ dispatchSessionStorageEventsToWindows(page, windows, key, oldValue, newValue, url, securityOrigin);
}
-void StorageEventDispatcher::dispatchLocalStorageEventsToFrames(PageGroup& pageGroup, const Vector<Ref<Frame>>& frames, const String& key, const String& oldValue, const String& newValue, const String& url, const SecurityOrigin& securityOrigin)
+void StorageEventDispatcher::dispatchLocalStorageEvents(const String& key, const String& oldValue, const String& newValue, PageGroup& pageGroup, const SecurityOrigin& securityOrigin, const String& url, const Function<bool(Storage&)>& isSourceStorage)
{
- for (auto& page : pageGroup.pages())
- InspectorInstrumentation::didDispatchDOMStorageEvent(page, key, oldValue, newValue, StorageType::Local, securityOrigin);
+ auto& pagesInGroup = pageGroup.pages();
+ Vector<Ref<DOMWindow>> windows;
+ DOMWindow::forEachWindowInterestedInStorageEvents([&](auto& window) {
+ if (!window.optionalLocalStorage())
+ return;
+ // Send events to every page in the group.
+ if (!window.page() || !pagesInGroup.contains(*window.page()))
+ return;
+ if (isSourceStorage(*window.optionalLocalStorage()))
+ return;
+ if (!securityOrigin.equal(window.securityOrigin()))
+ return;
+ windows.append(window);
+ });
- for (auto& frame : frames) {
- RefPtr document = frame->document();
- auto result = document->domWindow()->localStorage();
- if (!result.hasException()) // https://html.spec.whatwg.org/multipage/webstorage.html#the-storage-event:event-storage
- document->queueTaskToDispatchEventOnWindow(TaskSource::DOMManipulation, StorageEvent::create(eventNames().storageEvent, key, oldValue, newValue, url, result.releaseReturnValue()));
- }
+ dispatchLocalStorageEventsToWindows(pageGroup, windows, key, oldValue, newValue, url, securityOrigin);
}
} // namespace WebCore
Modified: trunk/Source/WebCore/storage/StorageEventDispatcher.h (290294 => 290295)
--- trunk/Source/WebCore/storage/StorageEventDispatcher.h 2022-02-22 09:42:11 UTC (rev 290294)
+++ trunk/Source/WebCore/storage/StorageEventDispatcher.h 2022-02-22 09:47:45 UTC (rev 290295)
@@ -33,21 +33,14 @@
namespace WebCore {
-class Frame;
class Page;
class PageGroup;
class SecurityOrigin;
+class Storage;
-class StorageEventDispatcher {
-public:
- WEBCORE_EXPORT static void dispatchSessionStorageEvents(const String& key, const String& oldValue, const String& newValue, const SecurityOrigin&, Frame* sourceFrame);
- WEBCORE_EXPORT static void dispatchLocalStorageEvents(const String& key, const String& oldValue, const String& newValue, const SecurityOrigin&, Frame* sourceFrame);
+namespace StorageEventDispatcher {
+WEBCORE_EXPORT void dispatchSessionStorageEvents(const String& key, const String& oldValue, const String& newValue, Page&, const SecurityOrigin&, const String& url, const Function<bool(Storage&)>& isSourceStorage);
+WEBCORE_EXPORT void dispatchLocalStorageEvents(const String& key, const String& oldValue, const String& newValue, PageGroup&, const SecurityOrigin&, const String& url, const Function<bool(Storage&)>& isSourceStorage);
+}
- WEBCORE_EXPORT static void dispatchSessionStorageEventsToFrames(Page&, const Vector<Ref<Frame>>& frames, const String& key, const String& oldValue, const String& newValue, const String& url, const SecurityOrigin&);
- WEBCORE_EXPORT static void dispatchLocalStorageEventsToFrames(PageGroup&, const Vector<Ref<Frame>>& frames, const String& key, const String& oldValue, const String& newValue, const String& url, const SecurityOrigin&);
-private:
- // Do not instantiate.
- StorageEventDispatcher();
-};
-
} // namespace WebCore
Modified: trunk/Source/WebKit/ChangeLog (290294 => 290295)
--- trunk/Source/WebKit/ChangeLog 2022-02-22 09:42:11 UTC (rev 290294)
+++ trunk/Source/WebKit/ChangeLog 2022-02-22 09:47:45 UTC (rev 290295)
@@ -1,3 +1,32 @@
+2022-02-22 Chris Dumez <[email protected]>
+
+ Avoid having to iterate the whole frame tree(s) every time we need to dispatch storage events
+ https://bugs.webkit.org/show_bug.cgi?id=236985
+
+ Reviewed by Darin Adler.
+
+ Avoid having to iterate the whole frame tree(s) every time we need to dispatch storage events,
+ by keeping track of window objects interested in storage events. A Window object is interested
+ in storage events if both of the following conditions is true:
+ 1. It has a Storage object (either localStorage or sessionStorage)
+ 2. It has a storage event listener registered.
+
+ This patch also refactors the code so that we share more logic between WebKit1 and WebKit2.
+
+ * WebProcess/WebStorage/StorageAreaImpl.cpp:
+ (WebKit::StorageAreaImpl::setItem):
+ (WebKit::StorageAreaImpl::removeItem):
+ (WebKit::StorageAreaImpl::clear):
+ * WebProcess/WebStorage/StorageAreaImpl.h:
+ * WebProcess/WebStorage/StorageAreaMap.cpp:
+ (WebKit::StorageAreaMap::setItem):
+ (WebKit::StorageAreaMap::removeItem):
+ (WebKit::StorageAreaMap::clear):
+ (WebKit::StorageAreaMap::dispatchSessionStorageEvent):
+ (WebKit::StorageAreaMap::dispatchLocalStorageEvent):
+ (WebKit::framesForEventDispatching): Deleted.
+ * WebProcess/WebStorage/StorageAreaMap.h:
+
2022-02-22 Kate Cheney <[email protected]>
NSSharingServicePicker gets deallocated when using the standard share menu item
Modified: trunk/Source/WebKit/WebProcess/WebStorage/StorageAreaImpl.cpp (290294 => 290295)
--- trunk/Source/WebKit/WebProcess/WebStorage/StorageAreaImpl.cpp 2022-02-22 09:42:11 UTC (rev 290294)
+++ trunk/Source/WebKit/WebProcess/WebStorage/StorageAreaImpl.cpp 2022-02-22 09:47:45 UTC (rev 290295)
@@ -70,7 +70,7 @@
return m_storageAreaMap ? m_storageAreaMap->item(key) : nullString();
}
-void StorageAreaImpl::setItem(Frame* sourceFrame, const String& key, const String& value, bool& quotaException)
+void StorageAreaImpl::setItem(Frame& sourceFrame, const String& key, const String& value, bool& quotaException)
{
ASSERT(!value.isNull());
@@ -78,13 +78,13 @@
m_storageAreaMap->setItem(sourceFrame, this, key, value, quotaException);
}
-void StorageAreaImpl::removeItem(Frame* sourceFrame, const String& key)
+void StorageAreaImpl::removeItem(Frame& sourceFrame, const String& key)
{
if (m_storageAreaMap)
m_storageAreaMap->removeItem(sourceFrame, this, key);
}
-void StorageAreaImpl::clear(Frame* sourceFrame)
+void StorageAreaImpl::clear(Frame& sourceFrame)
{
if (m_storageAreaMap)
m_storageAreaMap->clear(sourceFrame, this);
Modified: trunk/Source/WebKit/WebProcess/WebStorage/StorageAreaImpl.h (290294 => 290295)
--- trunk/Source/WebKit/WebProcess/WebStorage/StorageAreaImpl.h 2022-02-22 09:42:11 UTC (rev 290294)
+++ trunk/Source/WebKit/WebProcess/WebStorage/StorageAreaImpl.h 2022-02-22 09:47:45 UTC (rev 290295)
@@ -55,9 +55,9 @@
unsigned length() override;
String key(unsigned index) override;
String item(const String& key) override;
- void setItem(WebCore::Frame* sourceFrame, const String& key, const String& value, bool& quotaException) override;
- void removeItem(WebCore::Frame* sourceFrame, const String& key) override;
- void clear(WebCore::Frame* sourceFrame) override;
+ void setItem(WebCore::Frame& sourceFrame, const String& key, const String& value, bool& quotaException) override;
+ void removeItem(WebCore::Frame& sourceFrame, const String& key) override;
+ void clear(WebCore::Frame& sourceFrame) override;
bool contains(const String& key) override;
WebCore::StorageType storageType() const override;
size_t memoryBytesUsedByCache() override;
Modified: trunk/Source/WebKit/WebProcess/WebStorage/StorageAreaMap.cpp (290294 => 290295)
--- trunk/Source/WebKit/WebProcess/WebStorage/StorageAreaMap.cpp 2022-02-22 09:42:11 UTC (rev 290294)
+++ trunk/Source/WebKit/WebProcess/WebStorage/StorageAreaMap.cpp 2022-02-22 09:47:45 UTC (rev 290295)
@@ -82,7 +82,7 @@
return ensureMap().getItem(key);
}
-void StorageAreaMap::setItem(Frame* sourceFrame, StorageAreaImpl* sourceArea, const String& key, const String& value, bool& quotaException)
+void StorageAreaMap::setItem(Frame& sourceFrame, StorageAreaImpl* sourceArea, const String& key, const String& value, bool& quotaException)
{
auto& map = ensureMap();
ASSERT(!map.isShared());
@@ -108,10 +108,10 @@
weakThis->didSetItem(seed, key, hasQuotaException);
};
auto& connection = WebProcess::singleton().ensureNetworkProcessConnection().connection();
- connection.sendWithAsyncReply(Messages::NetworkStorageManager::SetItem(*m_remoteAreaIdentifier, sourceArea->identifier(), key, value, sourceFrame->document()->url().string()), WTFMove(callback));
+ connection.sendWithAsyncReply(Messages::NetworkStorageManager::SetItem(*m_remoteAreaIdentifier, sourceArea->identifier(), key, value, sourceFrame.document()->url().string()), WTFMove(callback));
}
-void StorageAreaMap::removeItem(WebCore::Frame* sourceFrame, StorageAreaImpl* sourceArea, const String& key)
+void StorageAreaMap::removeItem(WebCore::Frame& sourceFrame, StorageAreaImpl* sourceArea, const String& key)
{
auto& map = ensureMap();
ASSERT(!map.isShared());
@@ -133,10 +133,10 @@
if (weakThis)
weakThis->didRemoveItem(seed, key);
};
- WebProcess::singleton().ensureNetworkProcessConnection().connection().sendWithAsyncReply(Messages::NetworkStorageManager::RemoveItem(*m_remoteAreaIdentifier, sourceArea->identifier(), key, sourceFrame->document()->url().string()), WTFMove(callback));
+ WebProcess::singleton().ensureNetworkProcessConnection().connection().sendWithAsyncReply(Messages::NetworkStorageManager::RemoveItem(*m_remoteAreaIdentifier, sourceArea->identifier(), key, sourceFrame.document()->url().string()), WTFMove(callback));
}
-void StorageAreaMap::clear(WebCore::Frame* sourceFrame, StorageAreaImpl* sourceArea)
+void StorageAreaMap::clear(WebCore::Frame& sourceFrame, StorageAreaImpl* sourceArea)
{
connectSync();
resetValues();
@@ -153,7 +153,7 @@
if (weakThis)
weakThis->didClear(seed);
};
- WebProcess::singleton().ensureNetworkProcessConnection().connection().sendWithAsyncReply(Messages::NetworkStorageManager::Clear(*m_remoteAreaIdentifier, sourceArea->identifier(), sourceFrame->document()->url().string()), WTFMove(callback));
+ WebProcess::singleton().ensureNetworkProcessConnection().connection().sendWithAsyncReply(Messages::NetworkStorageManager::Clear(*m_remoteAreaIdentifier, sourceArea->identifier(), sourceFrame.document()->url().string()), WTFMove(callback));
}
bool StorageAreaMap::contains(const String& key)
@@ -296,43 +296,6 @@
resetValues();
}
-static Vector<Ref<Frame>> framesForEventDispatching(Page& page, const SecurityOrigin& origin, StorageType storageType, const std::optional<StorageAreaImplIdentifier>& storageAreaImplID)
-{
- Vector<Ref<Frame>> frames;
- page.forEachDocument([&](auto& document) {
- if (!document.securityOrigin().equal(&origin))
- return;
-
- auto* window = document.domWindow();
- if (!window || !window->hasEventListeners(eventNames().storageEvent))
- return;
-
- Storage* storage = nullptr;
- switch (storageType) {
- case StorageType::Session:
- storage = window->optionalSessionStorage();
- break;
- case StorageType::Local:
- case StorageType::TransientLocal:
- storage = window->optionalLocalStorage();
- break;
- }
-
- if (!storage)
- return;
-
- auto& storageArea = static_cast<StorageAreaImpl&>(storage->area());
- if (storageArea.identifier() == storageAreaImplID) {
- // This is the storage area that caused the event to be dispatched.
- return;
- }
-
- if (auto* frame = document.frame())
- frames.append(*frame);
- });
- return frames;
-}
-
void StorageAreaMap::dispatchSessionStorageEvent(const std::optional<StorageAreaImplIdentifier>& storageAreaImplID, const String& key, const String& oldValue, const String& newValue, const String& urlString)
{
// Namespace IDs for session storage namespaces are equivalent to web page IDs
@@ -345,8 +308,9 @@
if (!page)
return;
- auto frames = framesForEventDispatching(*page, m_securityOrigin, StorageType::Session, storageAreaImplID);
- StorageEventDispatcher::dispatchSessionStorageEventsToFrames(*page, frames, key, oldValue, newValue, urlString, m_securityOrigin);
+ StorageEventDispatcher::dispatchSessionStorageEvents(key, oldValue, newValue, *page, m_securityOrigin, urlString, [storageAreaImplID](auto& storage) {
+ return static_cast<StorageAreaImpl&>(storage.area()).identifier() == storageAreaImplID;
+ });
}
void StorageAreaMap::dispatchLocalStorageEvent(const std::optional<StorageAreaImplIdentifier>& storageAreaImplID, const String& key, const String& oldValue, const String& newValue, const String& urlString)
@@ -353,14 +317,11 @@
{
ASSERT(isLocalStorage(type()));
- Vector<Ref<Frame>> frames;
-
// Namespace IDs for local storage namespaces are currently equivalent to web page group IDs.
auto& pageGroup = *WebProcess::singleton().webPageGroup(m_namespace.pageGroupID())->corePageGroup();
- for (auto& page : pageGroup.pages())
- frames.appendVector(framesForEventDispatching(page, m_securityOrigin, StorageType::Local, storageAreaImplID));
-
- StorageEventDispatcher::dispatchLocalStorageEventsToFrames(pageGroup, frames, key, oldValue, newValue, urlString, m_securityOrigin);
+ StorageEventDispatcher::dispatchLocalStorageEvents(key, oldValue, newValue, pageGroup, m_securityOrigin, urlString, [storageAreaImplID](auto& storage) {
+ return static_cast<StorageAreaImpl&>(storage.area()).identifier() == storageAreaImplID;
+ });
}
void StorageAreaMap::sendConnectMessage(SendMode mode)
Modified: trunk/Source/WebKit/WebProcess/WebStorage/StorageAreaMap.h (290294 => 290295)
--- trunk/Source/WebKit/WebProcess/WebStorage/StorageAreaMap.h 2022-02-22 09:42:11 UTC (rev 290294)
+++ trunk/Source/WebKit/WebProcess/WebStorage/StorageAreaMap.h 2022-02-22 09:47:45 UTC (rev 290295)
@@ -58,9 +58,9 @@
unsigned length();
String key(unsigned index);
String item(const String& key);
- void setItem(WebCore::Frame* sourceFrame, StorageAreaImpl* sourceArea, const String& key, const String& value, bool& quotaException);
- void removeItem(WebCore::Frame* sourceFrame, StorageAreaImpl* sourceArea, const String& key);
- void clear(WebCore::Frame* sourceFrame, StorageAreaImpl* sourceArea);
+ void setItem(WebCore::Frame& sourceFrame, StorageAreaImpl* sourceArea, const String& key, const String& value, bool& quotaException);
+ void removeItem(WebCore::Frame& sourceFrame, StorageAreaImpl* sourceArea, const String& key);
+ void clear(WebCore::Frame& sourceFrame, StorageAreaImpl* sourceArea);
bool contains(const String& key);
// IPC::MessageReceiver
Modified: trunk/Source/WebKitLegacy/ChangeLog (290294 => 290295)
--- trunk/Source/WebKitLegacy/ChangeLog 2022-02-22 09:42:11 UTC (rev 290294)
+++ trunk/Source/WebKitLegacy/ChangeLog 2022-02-22 09:47:45 UTC (rev 290295)
@@ -1,3 +1,25 @@
+2022-02-22 Chris Dumez <[email protected]>
+
+ Avoid having to iterate the whole frame tree(s) every time we need to dispatch storage events
+ https://bugs.webkit.org/show_bug.cgi?id=236985
+
+ Reviewed by Darin Adler.
+
+ Avoid having to iterate the whole frame tree(s) every time we need to dispatch storage events,
+ by keeping track of window objects interested in storage events. A Window object is interested
+ in storage events if both of the following conditions is true:
+ 1. It has a Storage object (either localStorage or sessionStorage)
+ 2. It has a storage event listener registered.
+
+ This patch also refactors the code so that we share more logic between WebKit1 and WebKit2.
+
+ * Storage/StorageAreaImpl.cpp:
+ (WebKit::StorageAreaImpl::setItem):
+ (WebKit::StorageAreaImpl::removeItem):
+ (WebKit::StorageAreaImpl::clear):
+ (WebKit::StorageAreaImpl::dispatchStorageEvent):
+ * Storage/StorageAreaImpl.h:
+
2022-02-19 Chris Dumez <[email protected]>
Optimize DOM storage event dispatch
Modified: trunk/Source/WebKitLegacy/Storage/StorageAreaImpl.cpp (290294 => 290295)
--- trunk/Source/WebKitLegacy/Storage/StorageAreaImpl.cpp 2022-02-22 09:42:11 UTC (rev 290294)
+++ trunk/Source/WebKitLegacy/Storage/StorageAreaImpl.cpp 2022-02-22 09:47:45 UTC (rev 290295)
@@ -28,9 +28,12 @@
#include "StorageAreaSync.h"
#include "StorageSyncManager.h"
#include "StorageTracker.h"
+#include <WebCore/DOMWindow.h>
#include <WebCore/Frame.h>
+#include <WebCore/Page.h>
#include <WebCore/SecurityOrigin.h>
#include <WebCore/SecurityOriginData.h>
+#include <WebCore/Storage.h>
#include <WebCore/StorageEventDispatcher.h>
#include <WebCore/StorageType.h>
#include <wtf/MainThread.h>
@@ -121,7 +124,7 @@
return m_storageMap.getItem(key);
}
-void StorageAreaImpl::setItem(Frame* sourceFrame, const String& key, const String& value, bool& quotaException)
+void StorageAreaImpl::setItem(Frame& sourceFrame, const String& key, const String& value, bool& quotaException)
{
ASSERT(!m_isShutdown);
ASSERT(!value.isNull());
@@ -141,7 +144,7 @@
dispatchStorageEvent(key, oldValue, value, sourceFrame);
}
-void StorageAreaImpl::removeItem(Frame* sourceFrame, const String& key)
+void StorageAreaImpl::removeItem(Frame& sourceFrame, const String& key)
{
ASSERT(!m_isShutdown);
blockUntilImportComplete();
@@ -157,7 +160,7 @@
dispatchStorageEvent(key, oldValue, String(), sourceFrame);
}
-void StorageAreaImpl::clear(Frame* sourceFrame)
+void StorageAreaImpl::clear(Frame& sourceFrame)
{
ASSERT(!m_isShutdown);
blockUntilImportComplete();
@@ -269,12 +272,19 @@
}
}
-void StorageAreaImpl::dispatchStorageEvent(const String& key, const String& oldValue, const String& newValue, Frame* sourceFrame)
+void StorageAreaImpl::dispatchStorageEvent(const String& key, const String& oldValue, const String& newValue, Frame& sourceFrame)
{
+ auto* page = sourceFrame.page();
+ if (!page)
+ return;
+
+ auto isSourceStorage = [&sourceFrame](Storage& storage) {
+ return storage.frame() == &sourceFrame;
+ };
if (isLocalStorage(m_storageType))
- StorageEventDispatcher::dispatchLocalStorageEvents(key, oldValue, newValue, m_securityOrigin, sourceFrame);
+ StorageEventDispatcher::dispatchLocalStorageEvents(key, oldValue, newValue, page->group(), m_securityOrigin, sourceFrame.document()->url().string(), WTFMove(isSourceStorage));
else
- StorageEventDispatcher::dispatchSessionStorageEvents(key, oldValue, newValue, m_securityOrigin, sourceFrame);
+ StorageEventDispatcher::dispatchSessionStorageEvents(key, oldValue, newValue, *page, m_securityOrigin, sourceFrame.document()->url().string(), WTFMove(isSourceStorage));
}
void StorageAreaImpl::sessionChanged(bool isNewSessionPersistent)
Modified: trunk/Source/WebKitLegacy/Storage/StorageAreaImpl.h (290294 => 290295)
--- trunk/Source/WebKitLegacy/Storage/StorageAreaImpl.h 2022-02-22 09:42:11 UTC (rev 290294)
+++ trunk/Source/WebKitLegacy/Storage/StorageAreaImpl.h 2022-02-22 09:47:45 UTC (rev 290295)
@@ -49,9 +49,9 @@
unsigned length() override;
String key(unsigned index) override;
String item(const String& key) override;
- void setItem(WebCore::Frame* sourceFrame, const String& key, const String& value, bool& quotaException) override;
- void removeItem(WebCore::Frame* sourceFrame, const String& key) override;
- void clear(WebCore::Frame* sourceFrame) override;
+ void setItem(WebCore::Frame& sourceFrame, const String& key, const String& value, bool& quotaException) override;
+ void removeItem(WebCore::Frame& sourceFrame, const String& key) override;
+ void clear(WebCore::Frame& sourceFrame) override;
bool contains(const String& key) override;
WebCore::StorageType storageType() const override;
@@ -82,7 +82,7 @@
void blockUntilImportComplete() const;
void closeDatabaseTimerFired();
- void dispatchStorageEvent(const String& key, const String& oldValue, const String& newValue, WebCore::Frame* sourceFrame);
+ void dispatchStorageEvent(const String& key, const String& oldValue, const String& newValue, WebCore::Frame& sourceFrame);
WebCore::StorageType m_storageType;
Ref<const WebCore::SecurityOrigin> m_securityOrigin;