REGRESSION(r224267): WebViews scheduled with custom run loop modes don't load
authorachristensen@apple.com <achristensen@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 10 Nov 2017 17:30:59 +0000 (17:30 +0000)
committerachristensen@apple.com <achristensen@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 10 Nov 2017 17:30:59 +0000 (17:30 +0000)
https://bugs.webkit.org/show_bug.cgi?id=179515
Source/WebCore:

<rdar://problem/35445245>

Reviewed by Andy Estes.

Covered by a new API test which would have timed out without this change.

* platform/network/mac/WebCoreResourceHandleAsOperationQueueDelegate.mm:
(schedulePairHashSet):
Collect run loop modes from the NetworkingContext similarly to how we did before https://trac.webkit.org/changeset/224267/webkit#file40
(-[WebCoreResourceHandleAsOperationQueueDelegate connection:willSendRequest:redirectResponse:]):
(-[WebCoreResourceHandleAsOperationQueueDelegate connection:didReceiveAuthenticationChallenge:]):
(-[WebCoreResourceHandleAsOperationQueueDelegate connection:canAuthenticateAgainstProtectionSpace:]):
(-[WebCoreResourceHandleAsOperationQueueDelegate connection:didReceiveResponse:]):
(-[WebCoreResourceHandleAsOperationQueueDelegate connection:didReceiveData:lengthReceived:]):
(-[WebCoreResourceHandleAsOperationQueueDelegate connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:]):
(-[WebCoreResourceHandleAsOperationQueueDelegate connectionDidFinishLoading:]):
(-[WebCoreResourceHandleAsOperationQueueDelegate connection:didFailWithError:]):
(-[WebCoreResourceHandleAsOperationQueueDelegate connection:willCacheResponse:]):

Source/WTF:

<rdar://problem/35445245>

Reviewed by Andy Estes.

* wtf/MainThread.cpp:
(WTF::callOnMainThread):
* wtf/MainThread.h:
(WTF::callOnMainThread):
(WTF::scheduleDispatchFunctionsOnMainThread):
* wtf/generic/MainThreadGeneric.cpp:
(WTF::scheduleDispatchFunctionsOnMainThread):
* wtf/mac/MainThreadMac.mm:
(WTF::scheduleDispatchFunctionsOnMainThread):
* wtf/win/MainThreadWin.cpp:
(WTF::scheduleDispatchFunctionsOnMainThread):
Add an optional parameter which is an array of run loop mode names to pass to performSelectorOnMainThread.

Tools:

Reviewed by Andy Estes.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/mac/WebViewScheduleInRunLoop.mm: Added.
(-[ScheduleInRunLoopDelegate webView:didFinishLoadForFrame:]):
(TestWebKitAPI::TEST):

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

Source/WTF/ChangeLog
Source/WTF/wtf/MainThread.cpp
Source/WTF/wtf/MainThread.h
Source/WTF/wtf/generic/MainThreadGeneric.cpp
Source/WTF/wtf/mac/MainThreadMac.mm
Source/WTF/wtf/win/MainThreadWin.cpp
Source/WebCore/ChangeLog
Source/WebCore/platform/network/mac/WebCoreResourceHandleAsOperationQueueDelegate.mm
Tools/ChangeLog
Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
Tools/TestWebKitAPI/Tests/mac/WebViewScheduleInRunLoop.mm [new file with mode: 0644]

index 83588fe..b317663 100644 (file)
@@ -1,3 +1,24 @@
+2017-11-10  Alex Christensen  <achristensen@webkit.org>
+
+        REGRESSION(r224267): WebViews scheduled with custom run loop modes don't load
+        https://bugs.webkit.org/show_bug.cgi?id=179515
+        <rdar://problem/35445245>
+
+        Reviewed by Andy Estes.
+
+        * wtf/MainThread.cpp:
+        (WTF::callOnMainThread):
+        * wtf/MainThread.h:
+        (WTF::callOnMainThread):
+        (WTF::scheduleDispatchFunctionsOnMainThread):
+        * wtf/generic/MainThreadGeneric.cpp:
+        (WTF::scheduleDispatchFunctionsOnMainThread):
+        * wtf/mac/MainThreadMac.mm:
+        (WTF::scheduleDispatchFunctionsOnMainThread):
+        * wtf/win/MainThreadWin.cpp:
+        (WTF::scheduleDispatchFunctionsOnMainThread):
+        Add an optional parameter which is an array of run loop mode names to pass to performSelectorOnMainThread.
+
 2017-11-10  Ms2ger  <Ms2ger@igalia.com>
 
         Export tryFastZeroedMalloc.
index 161e7a3..45789a2 100644 (file)
@@ -142,7 +142,7 @@ void dispatchFunctionsFromMainThread()
     }
 }
 
-void callOnMainThread(Function<void ()>&& function)
+void callOnMainThread(Function<void()>&& function, SchedulePairHashSet* pairs)
 {
     ASSERT(function);
 
@@ -155,7 +155,7 @@ void callOnMainThread(Function<void ()>&& function)
     }
 
     if (needToSchedule)
-        scheduleDispatchFunctionsOnMainThread();
+        scheduleDispatchFunctionsOnMainThread(pairs);
 }
 
 void setMainThreadCallbacksPaused(bool paused)
index ab92134..99ab807 100644 (file)
@@ -31,6 +31,7 @@
 #define MainThread_h
 
 #include <stdint.h>
+#include <wtf/Forward.h>
 #include <wtf/Function.h>
 #include <wtf/Optional.h>
 #include <wtf/ThreadingPrimitives.h>
 namespace WTF {
 
 class PrintStream;
+class SchedulePair;
+struct SchedulePairHash;
+typedef HashSet<RefPtr<SchedulePair>, SchedulePairHash> SchedulePairHashSet;
 
 // Must be called from the main thread.
 WTF_EXPORT_PRIVATE void initializeMainThread();
 
-WTF_EXPORT_PRIVATE void callOnMainThread(Function<void ()>&&);
+WTF_EXPORT_PRIVATE void callOnMainThread(Function<void()>&&, SchedulePairHashSet* = nullptr);
 
 #if PLATFORM(COCOA)
 WTF_EXPORT_PRIVATE void callOnWebThreadOrDispatchAsyncOnMainThread(void (^block)());
@@ -81,7 +85,7 @@ WTF_EXPORT_PRIVATE bool isMainThreadOrGCThread();
 
 // NOTE: these functions are internal to the callOnMainThread implementation.
 void initializeMainThreadPlatform();
-void scheduleDispatchFunctionsOnMainThread();
+void scheduleDispatchFunctionsOnMainThread(SchedulePairHashSet* = nullptr);
 void dispatchFunctionsFromMainThread();
 
 #if OS(DARWIN) && !USE(GLIB)
index 91ad2e5..9d51746 100644 (file)
@@ -67,7 +67,7 @@ void initializeMainThreadPlatform()
 {
 }
 
-void scheduleDispatchFunctionsOnMainThread()
+void scheduleDispatchFunctionsOnMainThread(SchedulePairHashSet*)
 {
     // Use a RunLoop::Timer instead of RunLoop::dispatch() to be able to use a different priority and
     // avoid the double queue because dispatchOnMainThread also queues the functions.
index 272e3f5..6aef587 100644 (file)
@@ -35,6 +35,8 @@
 #import <stdio.h>
 #import <wtf/Assertions.h>
 #import <wtf/HashSet.h>
+#import <wtf/RetainPtr.h>
+#import <wtf/SchedulePair.h>
 #import <wtf/Threading.h>
 
 #if USE(WEB_THREAD)
@@ -120,7 +122,7 @@ static void postTimer()
     CFRunLoopAddTimer(CFRunLoopGetCurrent(), CFRunLoopTimerCreate(0, 0, 0, 0, 0, timerFired, 0), kCFRunLoopCommonModes);
 }
 
-void scheduleDispatchFunctionsOnMainThread()
+void scheduleDispatchFunctionsOnMainThread(SchedulePairHashSet* pairs)
 {
     ASSERT(staticMainThreadCaller);
 
@@ -129,14 +131,22 @@ void scheduleDispatchFunctionsOnMainThread()
         return;
     }
 
+    RetainPtr<NSArray<NSString *>> modes;
+    if (pairs) {
+        modes = adoptNS([[NSMutableArray alloc] initWithCapacity:pairs->size()]);
+        for (auto& pair : *pairs)
+            [(NSMutableArray *)modes.get() addObject:(NSString *)pair->mode()];
+    } else
+        modes = @[(NSString *)kCFRunLoopCommonModes];
+    
     if (mainThreadEstablishedAsPthreadMain) {
         ASSERT(!mainThreadNSThread);
-        [staticMainThreadCaller performSelectorOnMainThread:@selector(call) withObject:nil waitUntilDone:NO];
+        [staticMainThreadCaller performSelectorOnMainThread:@selector(call) withObject:nil waitUntilDone:NO modes:modes.get()];
         return;
     }
 
     ASSERT(mainThreadNSThread);
-    [staticMainThreadCaller performSelector:@selector(call) onThread:mainThreadNSThread withObject:nil waitUntilDone:NO];
+    [staticMainThreadCaller performSelector:@selector(call) onThread:mainThreadNSThread withObject:nil waitUntilDone:NO modes:modes.get()];
 }
 
 void callOnWebThreadOrDispatchAsyncOnMainThread(void (^block)())
index a6473d0..864967a 100644 (file)
@@ -67,7 +67,7 @@ void initializeMainThreadPlatform()
     Thread::initializeCurrentThreadInternal("Main Thread");
 }
 
-void scheduleDispatchFunctionsOnMainThread()
+void scheduleDispatchFunctionsOnMainThread(SchedulePairHashSet*)
 {
     ASSERT(threadingWindowHandle);
     PostMessage(threadingWindowHandle, threadingFiredMessage, 0, 0);
index 098681c..29b455e 100644 (file)
@@ -1,3 +1,26 @@
+2017-11-10  Alex Christensen  <achristensen@webkit.org>
+
+        REGRESSION(r224267): WebViews scheduled with custom run loop modes don't load
+        https://bugs.webkit.org/show_bug.cgi?id=179515
+        <rdar://problem/35445245>
+
+        Reviewed by Andy Estes.
+
+        Covered by a new API test which would have timed out without this change.
+
+        * platform/network/mac/WebCoreResourceHandleAsOperationQueueDelegate.mm:
+        (schedulePairHashSet):
+        Collect run loop modes from the NetworkingContext similarly to how we did before https://trac.webkit.org/changeset/224267/webkit#file40
+        (-[WebCoreResourceHandleAsOperationQueueDelegate connection:willSendRequest:redirectResponse:]):
+        (-[WebCoreResourceHandleAsOperationQueueDelegate connection:didReceiveAuthenticationChallenge:]):
+        (-[WebCoreResourceHandleAsOperationQueueDelegate connection:canAuthenticateAgainstProtectionSpace:]):
+        (-[WebCoreResourceHandleAsOperationQueueDelegate connection:didReceiveResponse:]):
+        (-[WebCoreResourceHandleAsOperationQueueDelegate connection:didReceiveData:lengthReceived:]):
+        (-[WebCoreResourceHandleAsOperationQueueDelegate connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:]):
+        (-[WebCoreResourceHandleAsOperationQueueDelegate connectionDidFinishLoading:]):
+        (-[WebCoreResourceHandleAsOperationQueueDelegate connection:didFailWithError:]):
+        (-[WebCoreResourceHandleAsOperationQueueDelegate connection:willCacheResponse:]):
+
 2017-11-10  Chris Dumez  <cdumez@apple.com>
 
         Simplify SWServerRegistration::forEachConnection()
index 7867a7e..1f7d6ce 100644 (file)
 
 using namespace WebCore;
 
+static SchedulePairHashSet* scheduledRunLoopPairs(ResourceHandle* handle)
+{
+    if (!handle)
+        return nullptr;
+    if (!handle->context())
+        return nullptr;
+    return handle->context()->scheduledRunLoopPairs();
+}
+
 @implementation WebCoreResourceHandleAsOperationQueueDelegate
 
 - (id)initWithHandle:(ResourceHandle*)handle messageQueue:(MessageQueue<Function<void()>>*)messageQueue
@@ -125,7 +134,7 @@ using namespace WebCore;
     if (m_messageQueue)
         m_messageQueue->append(std::make_unique<Function<void()>>(WTFMove(work)));
     else
-        callOnMainThread(WTFMove(work));
+        callOnMainThread(WTFMove(work), scheduledRunLoopPairs(m_handle));
 
     dispatch_semaphore_wait(m_semaphore, DISPATCH_TIME_FOREVER);
     return m_requestResult.get();
@@ -149,7 +158,7 @@ using namespace WebCore;
     if (m_messageQueue)
         m_messageQueue->append(std::make_unique<Function<void()>>(WTFMove(work)));
     else
-        callOnMainThread(WTFMove(work));
+        callOnMainThread(WTFMove(work), scheduledRunLoopPairs(m_handle));
 }
 
 - (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
@@ -171,7 +180,7 @@ using namespace WebCore;
     if (m_messageQueue)
         m_messageQueue->append(std::make_unique<Function<void()>>(WTFMove(work)));
     else
-        callOnMainThread(WTFMove(work));
+        callOnMainThread(WTFMove(work), scheduledRunLoopPairs(m_handle));
 
     dispatch_semaphore_wait(m_semaphore, DISPATCH_TIME_FOREVER);
     return m_boolResult;
@@ -210,7 +219,7 @@ using namespace WebCore;
     if (m_messageQueue)
         m_messageQueue->append(std::make_unique<Function<void()>>(WTFMove(work)));
     else
-        callOnMainThread(WTFMove(work));
+        callOnMainThread(WTFMove(work), scheduledRunLoopPairs(m_handle));
 
     dispatch_semaphore_wait(m_semaphore, DISPATCH_TIME_FOREVER);
 }
@@ -239,7 +248,7 @@ using namespace WebCore;
     if (m_messageQueue)
         m_messageQueue->append(std::make_unique<Function<void()>>(WTFMove(work)));
     else
-        callOnMainThread(WTFMove(work));
+        callOnMainThread(WTFMove(work), scheduledRunLoopPairs(m_handle));
 }
 
 - (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite
@@ -259,7 +268,7 @@ using namespace WebCore;
     if (m_messageQueue)
         m_messageQueue->append(std::make_unique<Function<void()>>(WTFMove(work)));
     else
-        callOnMainThread(WTFMove(work));
+        callOnMainThread(WTFMove(work), scheduledRunLoopPairs(m_handle));
 }
 
 - (void)connectionDidFinishLoading:(NSURLConnection *)connection
@@ -283,7 +292,7 @@ using namespace WebCore;
     if (m_messageQueue)
         m_messageQueue->append(std::make_unique<Function<void()>>(WTFMove(work)));
     else
-        callOnMainThread(WTFMove(work));
+        callOnMainThread(WTFMove(work), scheduledRunLoopPairs(m_handle));
 }
 
 - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
@@ -307,7 +316,7 @@ using namespace WebCore;
     if (m_messageQueue)
         m_messageQueue->append(std::make_unique<Function<void()>>(WTFMove(work)));
     else
-        callOnMainThread(WTFMove(work));
+        callOnMainThread(WTFMove(work), scheduledRunLoopPairs(m_handle));
 }
 
 
@@ -331,7 +340,7 @@ using namespace WebCore;
     if (m_messageQueue)
         m_messageQueue->append(std::make_unique<Function<void()>>(WTFMove(work)));
     else
-        callOnMainThread(WTFMove(work));
+        callOnMainThread(WTFMove(work), scheduledRunLoopPairs(m_handle));
 
     dispatch_semaphore_wait(m_semaphore, DISPATCH_TIME_FOREVER);
     return m_cachedResponseResult.get();
index 5917160..eb2ef13 100644 (file)
@@ -1,3 +1,15 @@
+2017-11-10  Alex Christensen  <achristensen@webkit.org>
+
+        REGRESSION(r224267): WebViews scheduled with custom run loop modes don't load
+        https://bugs.webkit.org/show_bug.cgi?id=179515
+
+        Reviewed by Andy Estes.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/mac/WebViewScheduleInRunLoop.mm: Added.
+        (-[ScheduleInRunLoopDelegate webView:didFinishLoadForFrame:]):
+        (TestWebKitAPI::TEST):
+
 2017-11-10  Fujii Hironori  <Hironori.Fujii@sony.com>
 
         [webkitpy] Fix PlatformInfo._win_version since r224657
index be87e58..b04ce51 100644 (file)
                5C6E65441D5CEFD400F7862E /* URLParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5C6E65411D5CEF8500F7862E /* URLParser.cpp */; };
                5C726D6F1D3EE06E00C5E1A1 /* InstanceMethodSwizzler.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5C726D6E1D3EE06800C5E1A1 /* InstanceMethodSwizzler.mm */; };
                5C7964101EB0278D0075D74C /* EventModifiers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5C79640F1EB0269B0075D74C /* EventModifiers.cpp */; };
+               5C7C74CB1FB529BA002F9ABE /* WebViewScheduleInRunLoop.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5C7C74CA1FB528D4002F9ABE /* WebViewScheduleInRunLoop.mm */; };
                5C838F7F1DB04F900082858F /* LoadInvalidURLRequest.mm in Sources */ = {isa = PBXBuildFile; fileRef = 57901FAE1CAF137100ED64F9 /* LoadInvalidURLRequest.mm */; };
                5C973F5C1F58EF8B00359C27 /* WebGLPolicy.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5C973F5B1F58EF0A00359C27 /* WebGLPolicy.mm */; };
                5C9E56851DF9145400C9EE33 /* WebsitePolicies.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5C9E56841DF9143D00C9EE33 /* WebsitePolicies.mm */; };
                5C726D6D1D3EE06800C5E1A1 /* InstanceMethodSwizzler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = InstanceMethodSwizzler.h; path = cocoa/InstanceMethodSwizzler.h; sourceTree = "<group>"; };
                5C726D6E1D3EE06800C5E1A1 /* InstanceMethodSwizzler.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = InstanceMethodSwizzler.mm; path = cocoa/InstanceMethodSwizzler.mm; sourceTree = "<group>"; };
                5C79640F1EB0269B0075D74C /* EventModifiers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EventModifiers.cpp; sourceTree = "<group>"; };
+               5C7C74CA1FB528D4002F9ABE /* WebViewScheduleInRunLoop.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebViewScheduleInRunLoop.mm; sourceTree = "<group>"; };
                5C973F5B1F58EF0A00359C27 /* WebGLPolicy.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebGLPolicy.mm; sourceTree = "<group>"; };
                5C9E56841DF9143D00C9EE33 /* WebsitePolicies.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebsitePolicies.mm; sourceTree = "<group>"; };
                5C9E56861DF9148E00C9EE33 /* contentBlockerCheck.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = contentBlockerCheck.html; sourceTree = "<group>"; };
                                C2EB2DD116CAC7AC009B52EE /* WebViewDidCreateJavaScriptContext.mm */,
                                37E38C33169B7D010084C28C /* WebViewDidRemoveFrameFromHierarchy.mm */,
                                51DB16CD1F085047001FA4C5 /* WebViewIconLoading.mm */,
+                               5C7C74CA1FB528D4002F9ABE /* WebViewScheduleInRunLoop.mm */,
                                CE32C7C718184C4900CD8C28 /* WillPerformClientRedirectToURLCrash.mm */,
                                1A7BFC0A171A0BDB00BC5F64 /* WillSendSubmitEvent.mm */,
                                A5E2027215B2181900C13E14 /* WindowlessWebViewWithMedia.mm */,
                                7CCE7ED51A411A7E00447C4C /* WebViewDidCreateJavaScriptContext.mm in Sources */,
                                7CCE7ED61A411A7E00447C4C /* WebViewDidRemoveFrameFromHierarchy.mm in Sources */,
                                51DB16CE1F085137001FA4C5 /* WebViewIconLoading.mm in Sources */,
+                               5C7C74CB1FB529BA002F9ABE /* WebViewScheduleInRunLoop.mm in Sources */,
                                7CCE7F1B1A411AE600447C4C /* WillLoad.cpp in Sources */,
                                7CCE7ED71A411A7E00447C4C /* WillPerformClientRedirectToURLCrash.mm in Sources */,
                                7CCE7F1C1A411AE600447C4C /* WillSendSubmitEvent.cpp in Sources */,
diff --git a/Tools/TestWebKitAPI/Tests/mac/WebViewScheduleInRunLoop.mm b/Tools/TestWebKitAPI/Tests/mac/WebViewScheduleInRunLoop.mm
new file mode 100644 (file)
index 0000000..1577428
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "PlatformUtilities.h"
+#import <CoreFoundation/CFRunLoop.h>
+#import <WebKit/WebFrameLoadDelegate.h>
+#import <WebKit/WebViewPrivate.h>
+#import <wtf/RetainPtr.h>
+
+@interface ScheduleInRunLoopDelegate : NSObject <WebFrameLoadDelegate> {
+}
+@end
+
+static bool didFinishLoad;
+
+@implementation ScheduleInRunLoopDelegate
+
+- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
+{
+    didFinishLoad = true;
+}
+
+@end
+
+namespace TestWebKitAPI {
+
+TEST(WebKitLegacy, ScheduleInRunLoop)
+{
+    auto webView = adoptNS([[WebView alloc] init]);
+    auto delegate = adoptNS([[ScheduleInRunLoopDelegate alloc] init]);
+    [webView setFrameLoadDelegate:delegate.get()];
+    [webView unscheduleFromRunLoop:[NSRunLoop currentRunLoop] forMode:(NSString *)kCFRunLoopCommonModes];
+    [webView scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:@"TestRunLoopMode"];
+    [[webView mainFrame] loadRequest:[NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"simple" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]]];
+
+    while (!didFinishLoad)
+        CFRunLoopRunInMode(CFSTR("TestRunLoopMode"), std::numeric_limits<double>::max(), true);
+}
+
+} // namespace TestWebKitAPI