Title: [248095] trunk
Revision
248095
Author
[email protected]
Date
2019-07-31 21:24:57 -0700 (Wed, 31 Jul 2019)

Log Message

REGRESSION (r240942): first visually non-empty layout milestone is not reached in media documents until after the video finishes loading
https://bugs.webkit.org/show_bug.cgi?id=200293
<rdar://problem/52937749>

Reviewed by Alex Christensen.

Source/WebCore:

r240942 changed FrameView::qualifiesAsVisuallyNonEmpty() to consider only documents in the
Interactive or Complete ready states as "finished parsing". Documents considered finished
parsing can qualify as visually non-empty even without exceeding the visual character or
pixel thresholds, but documents considered not finished must first exceed one of these
thresholds in order to qualify as visually non-empty.

HTMLDocuments are placed in the Interactive ready state by their HTMLDocumentParsers.
However, HTMLDocument subclasses like ImageDocument and MediaDocument use their own custom
parsers that never set the Interactive ready state on their documents; these documents go
from Loading directly to Complete.

In order for these HTMLDocument subclasses to be considered visually non-empty before they
finish loading they must render something that exceeds the visual character or pixel
thresholds. For image documents, rendering the image is usually enough to cross the
threshold, but for media documents the visual pixel threshold was never crossed because
videos did not contribute to the visually non-empty pixel count.

As a result, media documents are not considered visually non-empty until the main resource
finishes loading. On iOS this means that the layer tree remains frozen until this point,
even though the media might have started autoplaying with audio long before it finished
loading.

Fix this by teaching RenderVideo to contribute the video player's size to FrameView's
visually non-empty pixel count once the video player has loaded enough data to determine its
intrinsic size. Videos that render more than 1024 pixels will qualify a media document as
visually non-empty even when it is still loading its main resource.

Added a new API test.

* rendering/RenderImage.cpp:
(WebCore::RenderImage::imageChanged):
(WebCore::RenderImage::incrementVisuallyNonEmptyPixelCountIfNeeded):
* rendering/RenderImage.h:
* rendering/RenderVideo.cpp:
(WebCore::RenderVideo::updateIntrinsicSize):

Tools:

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKitCocoa/FirstVisuallyNonEmptyMilestone.mm: Renamed from Tools/TestWebKitAPI/Tests/WebKit/FirstVisuallyNonEmptyMilestoneWithDeferredScript.mm.
(-[FirstPaintMessageHandler userContentController:didReceiveScriptMessage:]):
(-[RenderingProgressNavigationDelegate _webView:renderingProgressDidChange:]):
(-[RenderingProgressNavigationDelegate webView:didFinishNavigation:]):
(TEST):

Modified Paths

Added Paths

Removed Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (248094 => 248095)


--- trunk/Source/WebCore/ChangeLog	2019-08-01 04:24:50 UTC (rev 248094)
+++ trunk/Source/WebCore/ChangeLog	2019-08-01 04:24:57 UTC (rev 248095)
@@ -1,3 +1,47 @@
+2019-07-31  Andy Estes  <[email protected]>
+
+        REGRESSION (r240942): first visually non-empty layout milestone is not reached in media documents until after the video finishes loading
+        https://bugs.webkit.org/show_bug.cgi?id=200293
+        <rdar://problem/52937749>
+
+        Reviewed by Alex Christensen.
+
+        r240942 changed FrameView::qualifiesAsVisuallyNonEmpty() to consider only documents in the
+        Interactive or Complete ready states as "finished parsing". Documents considered finished
+        parsing can qualify as visually non-empty even without exceeding the visual character or
+        pixel thresholds, but documents considered not finished must first exceed one of these
+        thresholds in order to qualify as visually non-empty.
+
+        HTMLDocuments are placed in the Interactive ready state by their HTMLDocumentParsers.
+        However, HTMLDocument subclasses like ImageDocument and MediaDocument use their own custom
+        parsers that never set the Interactive ready state on their documents; these documents go
+        from Loading directly to Complete.
+
+        In order for these HTMLDocument subclasses to be considered visually non-empty before they
+        finish loading they must render something that exceeds the visual character or pixel
+        thresholds. For image documents, rendering the image is usually enough to cross the
+        threshold, but for media documents the visual pixel threshold was never crossed because
+        videos did not contribute to the visually non-empty pixel count.
+
+        As a result, media documents are not considered visually non-empty until the main resource
+        finishes loading. On iOS this means that the layer tree remains frozen until this point,
+        even though the media might have started autoplaying with audio long before it finished
+        loading.
+
+        Fix this by teaching RenderVideo to contribute the video player's size to FrameView's
+        visually non-empty pixel count once the video player has loaded enough data to determine its
+        intrinsic size. Videos that render more than 1024 pixels will qualify a media document as
+        visually non-empty even when it is still loading its main resource.
+
+        Added a new API test.
+
+        * rendering/RenderImage.cpp:
+        (WebCore::RenderImage::imageChanged):
+        (WebCore::RenderImage::incrementVisuallyNonEmptyPixelCountIfNeeded):
+        * rendering/RenderImage.h:
+        * rendering/RenderVideo.cpp:
+        (WebCore::RenderVideo::updateIntrinsicSize):
+
 2019-07-31  Saam Barati  <[email protected]>
 
         [WHLSL] Remove UnnamedType copy/move constructors and mark classes as final

Modified: trunk/Source/WebCore/rendering/RenderImage.cpp (248094 => 248095)


--- trunk/Source/WebCore/rendering/RenderImage.cpp	2019-08-01 04:24:50 UTC (rev 248094)
+++ trunk/Source/WebCore/rendering/RenderImage.cpp	2019-08-01 04:24:57 UTC (rev 248095)
@@ -269,13 +269,10 @@
 
     if (newImage != imageResource().imagePtr() || !newImage)
         return;
-    
-    if (!m_didIncrementVisuallyNonEmptyPixelCount) {
-        // At a zoom level of 1 the image is guaranteed to have an integer size.
-        view().frameView().incrementVisuallyNonEmptyPixelCount(flooredIntSize(imageResource().imageSize(1.0f)));
-        m_didIncrementVisuallyNonEmptyPixelCount = true;
-    }
 
+    // At a zoom level of 1 the image is guaranteed to have an integer size.
+    incrementVisuallyNonEmptyPixelCountIfNeeded(flooredIntSize(imageResource().imageSize(1.0f)));
+
     ImageSizeChangeType imageSizeChange = ImageSizeChangeNone;
 
     // Set image dimensions, taking into account the size of the alt text.
@@ -850,4 +847,13 @@
     return nullptr;
 }
 
+void RenderImage::incrementVisuallyNonEmptyPixelCountIfNeeded(const IntSize& size)
+{
+    if (m_didIncrementVisuallyNonEmptyPixelCount)
+        return;
+
+    view().frameView().incrementVisuallyNonEmptyPixelCount(size);
+    m_didIncrementVisuallyNonEmptyPixelCount = true;
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/rendering/RenderImage.h (248094 => 248095)


--- trunk/Source/WebCore/rendering/RenderImage.h	2019-08-01 04:24:50 UTC (rev 248094)
+++ trunk/Source/WebCore/rendering/RenderImage.h	2019-08-01 04:24:57 UTC (rev 248095)
@@ -100,6 +100,8 @@
         imageChanged(imageResource().imagePtr());
     }
 
+    void incrementVisuallyNonEmptyPixelCountIfNeeded(const IntSize&);
+
 private:
     const char* renderName() const override { return "RenderImage"; }
 

Modified: trunk/Source/WebCore/rendering/RenderVideo.cpp (248094 => 248095)


--- trunk/Source/WebCore/rendering/RenderVideo.cpp	2019-08-01 04:24:50 UTC (rev 248094)
+++ trunk/Source/WebCore/rendering/RenderVideo.cpp	2019-08-01 04:24:57 UTC (rev 248095)
@@ -101,6 +101,10 @@
     if (size.isEmpty() && document().isMediaDocument())
         return false;
 
+    // Treat the media player's natural size as visually non-empty.
+    if (videoElement().readyState() >= HTMLMediaElementEnums::HAVE_METADATA)
+        incrementVisuallyNonEmptyPixelCountIfNeeded(roundedIntSize(size));
+
     if (size == intrinsicSize())
         return false;
 
@@ -109,7 +113,7 @@
     setNeedsLayout();
     return true;
 }
-    
+
 LayoutSize RenderVideo::calculateIntrinsicSize()
 {
     // Spec text from 4.8.6

Modified: trunk/Tools/ChangeLog (248094 => 248095)


--- trunk/Tools/ChangeLog	2019-08-01 04:24:50 UTC (rev 248094)
+++ trunk/Tools/ChangeLog	2019-08-01 04:24:57 UTC (rev 248095)
@@ -1,3 +1,18 @@
+2019-07-31  Andy Estes  <[email protected]>
+
+        REGRESSION (r240942): first visually non-empty layout milestone is not reached in media documents until after the video finishes loading
+        https://bugs.webkit.org/show_bug.cgi?id=200293
+        <rdar://problem/52937749>
+
+        Reviewed by Alex Christensen.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WebKitCocoa/FirstVisuallyNonEmptyMilestone.mm: Renamed from Tools/TestWebKitAPI/Tests/WebKit/FirstVisuallyNonEmptyMilestoneWithDeferredScript.mm.
+        (-[FirstPaintMessageHandler userContentController:didReceiveScriptMessage:]):
+        (-[RenderingProgressNavigationDelegate _webView:renderingProgressDidChange:]):
+        (-[RenderingProgressNavigationDelegate webView:didFinishNavigation:]):
+        (TEST):
+
 2019-07-31  Aakash Jain  <[email protected]>
 
         [ews-build] Enable all macOS queues on new EWS

Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (248094 => 248095)


--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2019-08-01 04:24:50 UTC (rev 248094)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2019-08-01 04:24:57 UTC (rev 248095)
@@ -65,7 +65,7 @@
 		1171B24F219F49CD00CB897D /* FirstMeaningfulPaintMilestone_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 11B7FD21219F46DD0069B27F /* FirstMeaningfulPaintMilestone_Bundle.cpp */; };
 		118153442208B7AC00B2CCD2 /* deferred-script-load.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 118153432208B7AC00B2CCD2 /* deferred-script-load.html */; };
 		118153462208B7E500B2CCD2 /* deferred-script.js in Copy Resources */ = {isa = PBXBuildFile; fileRef = 118153452208B7E500B2CCD2 /* deferred-script.js */; };
-		118153482208BADF00B2CCD2 /* FirstVisuallyNonEmptyMilestoneWithDeferredScript.mm in Sources */ = {isa = PBXBuildFile; fileRef = 118153472208BADF00B2CCD2 /* FirstVisuallyNonEmptyMilestoneWithDeferredScript.mm */; };
+		118153482208BADF00B2CCD2 /* FirstVisuallyNonEmptyMilestone.mm in Sources */ = {isa = PBXBuildFile; fileRef = 118153472208BADF00B2CCD2 /* FirstVisuallyNonEmptyMilestone.mm */; };
 		11B7FD28219F47110069B27F /* FirstMeaningfulPaintMilestone.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 11B7FD22219F46DD0069B27F /* FirstMeaningfulPaintMilestone.cpp */; };
 		11C2598D21FA6324004C9E23 /* async-script-load.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 11C2598C21FA618D004C9E23 /* async-script-load.html */; };
 		143DDE9820C9018B007F76FA /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 574F55D0204D471C002948C6 /* Security.framework */; };
@@ -1443,7 +1443,7 @@
 		115EB3421EE0B720003C2C0A /* ViewportSizeForViewportUnits.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ViewportSizeForViewportUnits.mm; sourceTree = "<group>"; };
 		118153432208B7AC00B2CCD2 /* deferred-script-load.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "deferred-script-load.html"; sourceTree = "<group>"; };
 		118153452208B7E500B2CCD2 /* deferred-script.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode._javascript_; path = "deferred-script.js"; sourceTree = "<group>"; };
-		118153472208BADF00B2CCD2 /* FirstVisuallyNonEmptyMilestoneWithDeferredScript.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FirstVisuallyNonEmptyMilestoneWithDeferredScript.mm; sourceTree = "<group>"; };
+		118153472208BADF00B2CCD2 /* FirstVisuallyNonEmptyMilestone.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FirstVisuallyNonEmptyMilestone.mm; sourceTree = "<group>"; };
 		11B7FD21219F46DD0069B27F /* FirstMeaningfulPaintMilestone_Bundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FirstMeaningfulPaintMilestone_Bundle.cpp; sourceTree = "<group>"; };
 		11B7FD22219F46DD0069B27F /* FirstMeaningfulPaintMilestone.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FirstMeaningfulPaintMilestone.cpp; sourceTree = "<group>"; };
 		11C2598C21FA618D004C9E23 /* async-script-load.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "async-script-load.html"; sourceTree = "<group>"; };
@@ -2705,6 +2705,7 @@
 				F44D06461F395C4D001A0E29 /* EditorStateTests.mm */,
 				CDA29B2820FD2A9900F15CED /* ExitFullscreenOnEnterPiP.mm */,
 				2D8104CB1BEC13E70020DA46 /* FindInPage.mm */,
+				118153472208BADF00B2CCD2 /* FirstVisuallyNonEmptyMilestone.mm */,
 				2D1FE0AF1AD465C1006CD9E6 /* FixedLayoutSize.mm */,
 				2E92B8F8216490EA005B64F0 /* FontAttributes.mm */,
 				5CB5B3BD1FFC517E00C27BB0 /* FrameHandleSerialization.mm */,
@@ -3396,7 +3397,6 @@
 				C51AFB98169F49FF009CCF66 /* FindMatches.mm */,
 				11B7FD22219F46DD0069B27F /* FirstMeaningfulPaintMilestone.cpp */,
 				11B7FD21219F46DD0069B27F /* FirstMeaningfulPaintMilestone_Bundle.cpp */,
-				118153472208BADF00B2CCD2 /* FirstVisuallyNonEmptyMilestoneWithDeferredScript.mm */,
 				1ADBEFAD130C689C00D61D19 /* ForceRepaint.cpp */,
 				376C8C041D6E197C007D2BB9 /* FrameHandle.cpp */,
 				BCBD370F125AA2EB00D2C29F /* FrameMIMETypeHTML.cpp */,
@@ -4373,7 +4373,7 @@
 				11B7FD28219F47110069B27F /* FirstMeaningfulPaintMilestone.cpp in Sources */,
 				7C83E0401D0A63E300FEBCF3 /* FirstResponderScrollingPosition.mm in Sources */,
 				C9E6DD351EA97D0800DD78AA /* FirstResponderSuppression.mm in Sources */,
-				118153482208BADF00B2CCD2 /* FirstVisuallyNonEmptyMilestoneWithDeferredScript.mm in Sources */,
+				118153482208BADF00B2CCD2 /* FirstVisuallyNonEmptyMilestone.mm in Sources */,
 				7C83E0BC1D0A650700FEBCF3 /* FixedLayoutSize.mm in Sources */,
 				7A909A7E1D877480007E10F8 /* FloatPoint.cpp in Sources */,
 				7A909A7F1D877480007E10F8 /* FloatRect.cpp in Sources */,

Deleted: trunk/Tools/TestWebKitAPI/Tests/WebKit/FirstVisuallyNonEmptyMilestoneWithDeferredScript.mm (248094 => 248095)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit/FirstVisuallyNonEmptyMilestoneWithDeferredScript.mm	2019-08-01 04:24:50 UTC (rev 248094)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit/FirstVisuallyNonEmptyMilestoneWithDeferredScript.mm	2019-08-01 04:24:57 UTC (rev 248095)
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2019 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 "TestNavigationDelegate.h"
-#import <wtf/RetainPtr.h>
-
-static bool didFirstVisuallyNonEmptyLayout;
-static bool receivedMessage;
-
-@interface FirstPaintMessageHandler : NSObject <WKScriptMessageHandler>
-@end
-
-@implementation FirstPaintMessageHandler
-- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
-{
-    receivedMessage = true;
-}
-@end
-
-@interface RenderingProgressNavigationDelegate : NSObject <WKNavigationDelegate>
-@end
-
-@implementation RenderingProgressNavigationDelegate
-- (void)_webView:(WKWebView *)webView renderingProgressDidChange:(_WKRenderingProgressEvents)progressEvents
-{
-    if (progressEvents & _WKRenderingProgressEventFirstVisuallyNonEmptyLayout)
-        didFirstVisuallyNonEmptyLayout = true;
-}
-@end
-
-TEST(WebKit, FirstVisuallyNonEmptyMilestoneWithDeferredScript)
-{
-    auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
-    auto messageHandler = adoptNS([[FirstPaintMessageHandler alloc] init]);
-    [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"firstpaint"];
-
-    auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
-
-    RetainPtr<RenderingProgressNavigationDelegate> delegate = adoptNS([[RenderingProgressNavigationDelegate alloc] init]);
-    [webView setNavigationDelegate:delegate.get()];
-
-    receivedMessage = false;
-    didFirstVisuallyNonEmptyLayout = false;
-
-    [webView loadRequest:[NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"deferred-script-load" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]]];
-
-    TestWebKitAPI::Util::run(&receivedMessage);
-    EXPECT_TRUE(didFirstVisuallyNonEmptyLayout);
-}

Copied: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/FirstVisuallyNonEmptyMilestone.mm (from rev 248088, trunk/Tools/TestWebKitAPI/Tests/WebKit/FirstVisuallyNonEmptyMilestoneWithDeferredScript.mm) (0 => 248095)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/FirstVisuallyNonEmptyMilestone.mm	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/FirstVisuallyNonEmptyMilestone.mm	2019-08-01 04:24:57 UTC (rev 248095)
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2019 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 "TestNavigationDelegate.h"
+#import "TestWKWebView.h"
+#import <WebKit/WKWebViewConfigurationPrivate.h>
+#import <wtf/RetainPtr.h>
+
+#if PLATFORM(IOS_FAMILY)
+#include <MobileCoreServices/MobileCoreServices.h>
+#endif
+
+static bool didFirstVisuallyNonEmptyLayout;
+static bool receivedMessage;
+
+@interface FirstPaintMessageHandler : NSObject <WKScriptMessageHandler>
+@end
+
+@implementation FirstPaintMessageHandler
+- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
+{
+    receivedMessage = true;
+}
+@end
+
+@interface RenderingProgressNavigationDelegate : NSObject <WKNavigationDelegate>
+@end
+
+@implementation RenderingProgressNavigationDelegate
+- (void)_webView:(WKWebView *)webView renderingProgressDidChange:(_WKRenderingProgressEvents)progressEvents
+{
+    if (progressEvents & _WKRenderingProgressEventFirstVisuallyNonEmptyLayout)
+        didFirstVisuallyNonEmptyLayout = true;
+}
+@end
+
+TEST(WebKit, FirstVisuallyNonEmptyMilestoneWithDeferredScript)
+{
+    auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    auto messageHandler = adoptNS([[FirstPaintMessageHandler alloc] init]);
+    [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"firstpaint"];
+
+    auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
+
+    RetainPtr<RenderingProgressNavigationDelegate> delegate = adoptNS([[RenderingProgressNavigationDelegate alloc] init]);
+    [webView setNavigationDelegate:delegate.get()];
+
+    receivedMessage = false;
+    didFirstVisuallyNonEmptyLayout = false;
+
+    [webView loadRequest:[NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"deferred-script-load" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]]];
+
+    TestWebKitAPI::Util::run(&receivedMessage);
+    EXPECT_TRUE(didFirstVisuallyNonEmptyLayout);
+}
+
+@interface NeverFinishLoadingSchemeHandler : NSObject <WKURLSchemeHandler>
+@property (nonatomic, readonly, class) NSString *URLScheme;
+@end
+
+@implementation NeverFinishLoadingSchemeHandler
+
++ (NSString *)URLScheme
+{
+    return @"never-finish-loading";
+}
+
+static NSString *contentTypeForFileExtension(NSString *fileExtension)
+{
+    auto identifier = adoptCF(UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)fileExtension, nullptr));
+    auto mimeType = adoptCF(UTTypeCopyPreferredTagWithClass(identifier.get(), kUTTagClassMIMEType));
+    return (__bridge NSString *)mimeType.autorelease();
+}
+
+- (void)webView:(WKWebView *)webView startURLSchemeTask:(id <WKURLSchemeTask>)task
+{
+    NSURL *requestURL = task.request.URL;
+    NSString *fileName = requestURL.lastPathComponent;
+    NSString *fileExtension = fileName.pathExtension;
+    NSURL *bundleURL = [NSBundle.mainBundle URLForResource:fileName.stringByDeletingPathExtension withExtension:fileExtension subdirectory:@"TestWebKitAPI.resources"];
+
+    NSData *responseData = [NSData dataWithContentsOfURL:bundleURL];
+    NSUInteger responseLength = responseData.length;
+
+    auto response = adoptNS([[NSURLResponse alloc] initWithURL:requestURL MIMEType:contentTypeForFileExtension(fileExtension) expectedContentLength:responseLength textEncodingName:nil]);
+    [task didReceiveResponse:response.get()];
+
+    [task didReceiveData:[responseData subdataWithRange:NSMakeRange(0, responseLength - 1024)]];
+}
+
+- (void)webView:(WKWebView *)webView stopURLSchemeTask:(id <WKURLSchemeTask>)task
+{
+}
+
+@end
+
+TEST(WebKit, FirstVisuallyNonEmptyMilestoneWithMediaDocument)
+{
+    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+#if PLATFORM(IOS_FAMILY)
+    [configuration setAllowsInlineMediaPlayback:YES];
+    [configuration _setInlineMediaPlaybackRequiresPlaysInlineAttribute:NO];
+#endif
+
+    auto schemeHandler = adoptNS([[NeverFinishLoadingSchemeHandler alloc] init]);
+    [configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:NeverFinishLoadingSchemeHandler.URLScheme];
+
+    auto navigationDelegate = adoptNS([[RenderingProgressNavigationDelegate alloc] init]);
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration.get() addToWindow:YES]);
+    [webView setNavigationDelegate:navigationDelegate.get()];
+    [webView _setAllowsMediaDocumentInlinePlayback:YES];
+
+    [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"never-finish-loading:///large-video-with-audio.mp4"]]];
+
+    didFirstVisuallyNonEmptyLayout = false;
+    TestWebKitAPI::Util::run(&didFirstVisuallyNonEmptyLayout);
+}
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to