- Revision
- 265510
- Author
- [email protected]
- Date
- 2020-08-11 12:52:31 -0700 (Tue, 11 Aug 2020)
Log Message
Deferred WKUserScripts are exponentially injected on preloaded pages with frames.
https://bugs.webkit.org/show_bug.cgi?id=215382
rdar://problem/66837802
Reviewed by Sam Weinig.
Source/WebCore:
When defering a script in a frame it was previously added to a vector per-page.
Later when notified to inject the defered scripts, the page would iterate over all
the frames and evaluate the scripts on each frame. Since this vector had all the
frame's scripts the evaluations would be multiplied by the number of frames.
Now the defered scripts are stored per-frame and the page asks each frame to
inject the defered scripts.
* page/Frame.cpp:
(WebCore::Frame::injectUserScripts):
(WebCore::Frame::addUserScriptAwaitingNotification):
(WebCore::Frame::injectUserScriptsAwaitingNotification):
* page/Frame.h:
* page/Page.cpp:
(WebCore::Page::notifyToInjectUserScripts):
(WebCore::Page::addUserScriptAwaitingNotification): Deleted.
* page/Page.h:
* page/Quirks.cpp:
(WebCore::Quirks::triggerOptionalStorageAccessQuirk const):
Tools:
* TestWebKitAPI/Tests/WebKitCocoa/UserContentController.mm:
(TEST):
Modified Paths
Diff
Modified: trunk/Source/WebCore/ChangeLog (265509 => 265510)
--- trunk/Source/WebCore/ChangeLog 2020-08-11 19:45:57 UTC (rev 265509)
+++ trunk/Source/WebCore/ChangeLog 2020-08-11 19:52:31 UTC (rev 265510)
@@ -1,3 +1,31 @@
+2020-08-11 Timothy Hatcher <[email protected]>
+
+ Deferred WKUserScripts are exponentially injected on preloaded pages with frames.
+ https://bugs.webkit.org/show_bug.cgi?id=215382
+ rdar://problem/66837802
+
+ Reviewed by Sam Weinig.
+
+ When defering a script in a frame it was previously added to a vector per-page.
+ Later when notified to inject the defered scripts, the page would iterate over all
+ the frames and evaluate the scripts on each frame. Since this vector had all the
+ frame's scripts the evaluations would be multiplied by the number of frames.
+
+ Now the defered scripts are stored per-frame and the page asks each frame to
+ inject the defered scripts.
+
+ * page/Frame.cpp:
+ (WebCore::Frame::injectUserScripts):
+ (WebCore::Frame::addUserScriptAwaitingNotification):
+ (WebCore::Frame::injectUserScriptsAwaitingNotification):
+ * page/Frame.h:
+ * page/Page.cpp:
+ (WebCore::Page::notifyToInjectUserScripts):
+ (WebCore::Page::addUserScriptAwaitingNotification): Deleted.
+ * page/Page.h:
+ * page/Quirks.cpp:
+ (WebCore::Quirks::triggerOptionalStorageAccessQuirk const):
+
2020-08-11 Wenson Hsieh <[email protected]>
Text input autocorrect="off" attribute ignored on Mac
Modified: trunk/Source/WebCore/page/Frame.cpp (265509 => 265510)
--- trunk/Source/WebCore/page/Frame.cpp 2020-08-11 19:45:57 UTC (rev 265509)
+++ trunk/Source/WebCore/page/Frame.cpp 2020-08-11 19:52:31 UTC (rev 265510)
@@ -648,7 +648,7 @@
m_page->userContentProvider().forEachUserScript([this, protectedThis = makeRef(*this), injectionTime, pageWasNotified] (DOMWrapperWorld& world, const UserScript& script) {
if (script.injectionTime() == injectionTime) {
if (script.waitForNotificationBeforeInjecting() == WaitForNotificationBeforeInjecting::Yes && !pageWasNotified)
- m_page->addUserScriptAwaitingNotification(world, script);
+ addUserScriptAwaitingNotification(world, script);
else
injectUserScriptImmediately(world, script);
}
@@ -680,6 +680,17 @@
m_script->evaluateInWorldIgnoringException(ScriptSourceCode(script.source(), URL(script.url())), world);
}
+void Frame::addUserScriptAwaitingNotification(DOMWrapperWorld& world, const UserScript& script)
+{
+ m_userScriptsAwaitingNotification.append({ makeRef(world), makeUniqueRef<UserScript>(script) });
+}
+
+void Frame::injectUserScriptsAwaitingNotification()
+{
+ for (const auto& [world, script] : std::exchange(m_userScriptsAwaitingNotification, { }))
+ injectUserScriptImmediately(world, script.get());
+}
+
Optional<PageIdentifier> Frame::pageID() const
{
return loader().pageID();
Modified: trunk/Source/WebCore/page/Frame.h (265509 => 265510)
--- trunk/Source/WebCore/page/Frame.h 2020-08-11 19:45:57 UTC (rev 265509)
+++ trunk/Source/WebCore/page/Frame.h 2020-08-11 19:52:31 UTC (rev 265510)
@@ -198,7 +198,10 @@
WEBCORE_EXPORT void injectUserScripts(UserScriptInjectionTime);
WEBCORE_EXPORT void injectUserScriptImmediately(DOMWrapperWorld&, const UserScript&);
-
+
+ void injectUserScriptsAwaitingNotification();
+ void addUserScriptAwaitingNotification(DOMWrapperWorld&, const UserScript&);
+
WEBCORE_EXPORT String layerTreeAsText(LayerTreeFlags = 0) const;
WEBCORE_EXPORT String trackedRepaintRectsAsText() const;
@@ -328,6 +331,8 @@
HashSet<FrameDestructionObserver*> m_destructionObservers;
+ Vector<std::pair<Ref<DOMWrapperWorld>, UniqueRef<UserScript>>> m_userScriptsAwaitingNotification;
+
Frame& m_mainFrame;
Page* m_page;
const RefPtr<Settings> m_settings;
Modified: trunk/Source/WebCore/page/Page.cpp (265509 => 265510)
--- trunk/Source/WebCore/page/Page.cpp 2020-08-11 19:45:57 UTC (rev 265509)
+++ trunk/Source/WebCore/page/Page.cpp 2020-08-11 19:52:31 UTC (rev 265510)
@@ -2673,19 +2673,10 @@
{
m_hasBeenNotifiedToInjectUserScripts = true;
- for (auto* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
- for (const auto& pair : m_userScriptsAwaitingNotification)
- frame->injectUserScriptImmediately(pair.first, pair.second.get());
- }
-
- m_userScriptsAwaitingNotification.clear();
+ for (auto* frame = &mainFrame(); frame; frame = frame->tree().traverseNext())
+ frame->injectUserScriptsAwaitingNotification();
}
-void Page::addUserScriptAwaitingNotification(DOMWrapperWorld& world, const UserScript& script)
-{
- m_userScriptsAwaitingNotification.append({ makeRef(world), makeUniqueRef<UserScript>(script) });
-}
-
void Page::setUserContentProvider(Ref<UserContentProvider>&& userContentProvider)
{
m_userContentProvider->removePage(*this);
Modified: trunk/Source/WebCore/page/Page.h (265509 => 265510)
--- trunk/Source/WebCore/page/Page.h 2020-08-11 19:45:57 UTC (rev 265509)
+++ trunk/Source/WebCore/page/Page.h 2020-08-11 19:52:31 UTC (rev 265510)
@@ -775,7 +775,6 @@
bool hasBeenNotifiedToInjectUserScripts() const { return m_hasBeenNotifiedToInjectUserScripts; }
WEBCORE_EXPORT void notifyToInjectUserScripts();
- void addUserScriptAwaitingNotification(DOMWrapperWorld&, const UserScript&);
private:
struct Navigation {
@@ -1070,7 +1069,6 @@
bool m_loadsFromNetwork { true };
ShouldRelaxThirdPartyCookieBlocking m_shouldRelaxThirdPartyCookieBlocking { ShouldRelaxThirdPartyCookieBlocking::No };
bool m_hasBeenNotifiedToInjectUserScripts { false };
- Vector<std::pair<Ref<DOMWrapperWorld>, UniqueRef<UserScript>>> m_userScriptsAwaitingNotification;
};
inline PageGroup& Page::group()
Modified: trunk/Source/WebCore/page/Quirks.cpp (265509 => 265510)
--- trunk/Source/WebCore/page/Quirks.cpp 2020-08-11 19:45:57 UTC (rev 265509)
+++ trunk/Source/WebCore/page/Quirks.cpp 2020-08-11 19:52:31 UTC (rev 265510)
@@ -965,11 +965,9 @@
auto* abstractFrame = proxy->frame();
if (abstractFrame && is<Frame>(*abstractFrame)) {
auto& frame = downcast<Frame>(*abstractFrame);
- if (auto* page = frame.page()) {
- auto world = ScriptController::createWorld("kinjaComQuirkWorld", ScriptController::WorldType::User);
- page->addUserScriptAwaitingNotification(world.get(), kinjaLoginUserScript);
- return Quirks::StorageAccessResult::ShouldCancelEvent;
- }
+ auto world = ScriptController::createWorld("kinjaComQuirkWorld", ScriptController::WorldType::User);
+ frame.addUserScriptAwaitingNotification(world.get(), kinjaLoginUserScript);
+ return Quirks::StorageAccessResult::ShouldCancelEvent;
}
}
}
Modified: trunk/Tools/ChangeLog (265509 => 265510)
--- trunk/Tools/ChangeLog 2020-08-11 19:45:57 UTC (rev 265509)
+++ trunk/Tools/ChangeLog 2020-08-11 19:52:31 UTC (rev 265510)
@@ -1,3 +1,14 @@
+2020-08-11 Timothy Hatcher <[email protected]>
+
+ Deferred WKUserScripts are exponentially injected on preloaded pages with frames.
+ https://bugs.webkit.org/show_bug.cgi?id=215382
+ rdar://problem/66837802
+
+ Reviewed by Sam Weinig.
+
+ * TestWebKitAPI/Tests/WebKitCocoa/UserContentController.mm:
+ (TEST):
+
2020-08-11 Sihui Liu <[email protected]>
Text manipulation crashes when replacing element with img role
Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/UserContentController.mm (265509 => 265510)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/UserContentController.mm 2020-08-11 19:45:57 UTC (rev 265509)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/UserContentController.mm 2020-08-11 19:52:31 UTC (rev 265510)
@@ -945,6 +945,18 @@
EXPECT_FALSE(webView3._deferrableUserScriptsNeedNotification);
EXPECT_WK_STREQ([delegate waitForAlert], "waited for notification");
EXPECT_WK_STREQ([delegate waitForAlert], "document parsing ended");
+
+ TestWKWebView *webView4 = [[TestWKWebView new] autorelease];
+ EXPECT_TRUE(webView4._deferrableUserScriptsNeedNotification);
+ [webView4.configuration.userContentController addUserScript:waitsForNotification];
+ [webView4.configuration.userContentController addUserScript:documentEnd];
+ webView4.UIDelegate = delegate;
+ [webView4 loadTestPageNamed:@"simple-iframe"];
+ [webView4 _notifyUserScripts];
+
+ // If this is broken, two alerts would appear back-to-back with the same text due to the frame.
+ EXPECT_WK_STREQ([delegate waitForAlert], "waited for notification");
+ EXPECT_WK_STREQ([delegate waitForAlert], "document parsing ended");
}
@interface AsyncScriptMessageHandler : NSObject <WKScriptMessageHandlerWithReply>