Let clients control autoplay quirks with website policies.
authormrajca@apple.com <mrajca@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 9 Mar 2017 20:47:10 +0000 (20:47 +0000)
committermrajca@apple.com <mrajca@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 9 Mar 2017 20:47:10 +0000 (20:47 +0000)
https://bugs.webkit.org/show_bug.cgi?id=169390

Reviewed by Wenson Hsieh.

Many sites incorrectly assume media will start off playing and display a pause button from the
start. We can trick many of these sites into updating their controls by sending a "pause"
event when we prevent a media element from playing.

We don't want this to become standard web behavior, however, since ultimately sites should adapt
to the new behavior. This patch lets clients decide which limited set of sites gets to use auto-play
quirks.

Source/WebCore:

* html/HTMLMediaElement.cpp:
(WebCore::needsAutoplayPlayPauseEventsQuirk):
* loader/DocumentLoader.h:
(WebCore::DocumentLoader::allowsAutoplayQuirks):
(WebCore::DocumentLoader::setAllowsAutoplayQuirks):

Source/WebKit2:

* Shared/WebsitePolicies.h:
(WebKit::WebsitePolicies::encode):
(WebKit::WebsitePolicies::decode):
* UIProcess/API/APIWebsitePolicies.h:
* UIProcess/API/C/WKWebsitePolicies.cpp:
(WKWebsitePoliciesSetAllowsAutoplayQuirks):
(WKWebsitePoliciesGetAllowsAutoplayQuirks):
* UIProcess/API/C/WKWebsitePolicies.h:
* UIProcess/API/Cocoa/_WKWebsitePolicies.h:
* UIProcess/API/Cocoa/_WKWebsitePolicies.mm:
(-[_WKWebsitePolicies setAllowsAutoplayQuirks:]):
(-[_WKWebsitePolicies allowsAutoplayQuirks]):
* WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
(WebKit::WebFrameLoaderClient::dispatchDecidePolicyForNavigationAction):
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::updateWebsitePolicies):

Tools:

* TestWebKitAPI/Tests/WebKit2/autoplay-check.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/WebsitePolicies.mm:
(-[AutoplayPoliciesDelegate _webView:decidePolicyForNavigationAction:decisionHandler:]):
(TEST):

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

15 files changed:
Source/WebCore/ChangeLog
Source/WebCore/html/HTMLMediaElement.cpp
Source/WebCore/loader/DocumentLoader.h
Source/WebKit2/ChangeLog
Source/WebKit2/Shared/WebsitePolicies.h
Source/WebKit2/UIProcess/API/APIWebsitePolicies.h
Source/WebKit2/UIProcess/API/C/WKWebsitePolicies.cpp
Source/WebKit2/UIProcess/API/C/WKWebsitePolicies.h
Source/WebKit2/UIProcess/API/Cocoa/_WKWebsitePolicies.h
Source/WebKit2/UIProcess/API/Cocoa/_WKWebsitePolicies.mm
Source/WebKit2/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp
Source/WebKit2/WebProcess/WebPage/WebPage.cpp
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/WebKit2/autoplay-check.html
Tools/TestWebKitAPI/Tests/WebKit2Cocoa/WebsitePolicies.mm

index d53584d..aa56627 100644 (file)
@@ -1,3 +1,26 @@
+2017-03-08  Matt Rajca  <mrajca@apple.com>
+
+        Let clients control autoplay quirks with website policies.
+        https://bugs.webkit.org/show_bug.cgi?id=169390
+
+        Reviewed by Wenson Hsieh.
+
+        Added API tests.
+
+        Many sites incorrectly assume media will start off playing and display a pause button from the
+        start. We can trick many of these sites into updating their controls by sending a "pause"
+        event when we prevent a media element from playing.
+
+        We don't want this to become standard web behavior, however, since ultimately sites should adapt
+        to the new behavior. This patch lets clients decide which limited set of sites gets to use auto-play
+        quirks.
+
+        * html/HTMLMediaElement.cpp:
+        (WebCore::needsAutoplayPlayPauseEventsQuirk):
+        * loader/DocumentLoader.h:
+        (WebCore::DocumentLoader::allowsAutoplayQuirks):
+        (WebCore::DocumentLoader::setAllowsAutoplayQuirks):
+
 2017-03-09  Mark Lam  <mark.lam@apple.com>
 
         Make the VM Traps mechanism non-polling for the DFG and FTL.
index 5eb207a..523c2e5 100644 (file)
@@ -591,8 +591,8 @@ static bool needsAutoplayPlayPauseEventsQuirk(const Document& document)
     if (!page || !page->settings().needsSiteSpecificQuirks())
         return false;
 
-    String host = document.url().host();
-    return equalLettersIgnoringASCIICase(host, "yahoo.com") || host.endsWithIgnoringASCIICase(".yahoo.com");
+    auto* loader = document.loader();
+    return loader && loader->allowsAutoplayQuirks();
 }
 
 static bool needsPlaybackControlsManagerQuirk(Page& page)
index 0ad372a..7da400a 100644 (file)
@@ -242,6 +242,9 @@ public:
     AutoplayPolicy autoplayPolicy() const { return m_autoplayPolicy; }
     void setAutoplayPolicy(AutoplayPolicy policy) { m_autoplayPolicy = policy; }
 
+    bool allowsAutoplayQuirks() const { return m_allowsAutoplayQuirks; }
+    void setAllowsAutoplayQuirks(bool allowsQuirks) { m_allowsAutoplayQuirks = allowsQuirks; }
+
     void addSubresourceLoader(ResourceLoader*);
     void removeSubresourceLoader(ResourceLoader*);
     void addPlugInStreamLoader(ResourceLoader&);
@@ -472,6 +475,7 @@ private:
 #endif
     bool m_userContentExtensionsEnabled { true };
     AutoplayPolicy m_autoplayPolicy { AutoplayPolicy::Default };
+    bool m_allowsAutoplayQuirks { false };
 
 #ifndef NDEBUG
     bool m_hasEverBeenAttached { false };
index d810a28..f733288 100644 (file)
@@ -1,3 +1,35 @@
+2017-03-08  Matt Rajca  <mrajca@apple.com>
+
+        Let clients control autoplay quirks with website policies.
+        https://bugs.webkit.org/show_bug.cgi?id=169390
+
+        Reviewed by Wenson Hsieh.
+        
+        Many sites incorrectly assume media will start off playing and display a pause button from the
+        start. We can trick many of these sites into updating their controls by sending a "pause"
+        event when we prevent a media element from playing.
+
+        We don't want this to become standard web behavior, however, since ultimately sites should adapt
+        to the new behavior. This patch lets clients decide which limited set of sites gets to use auto-play
+        quirks.
+
+        * Shared/WebsitePolicies.h:
+        (WebKit::WebsitePolicies::encode):
+        (WebKit::WebsitePolicies::decode):
+        * UIProcess/API/APIWebsitePolicies.h:
+        * UIProcess/API/C/WKWebsitePolicies.cpp:
+        (WKWebsitePoliciesSetAllowsAutoplayQuirks):
+        (WKWebsitePoliciesGetAllowsAutoplayQuirks):
+        * UIProcess/API/C/WKWebsitePolicies.h:
+        * UIProcess/API/Cocoa/_WKWebsitePolicies.h:
+        * UIProcess/API/Cocoa/_WKWebsitePolicies.mm:
+        (-[_WKWebsitePolicies setAllowsAutoplayQuirks:]):
+        (-[_WKWebsitePolicies allowsAutoplayQuirks]):
+        * WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
+        (WebKit::WebFrameLoaderClient::dispatchDecidePolicyForNavigationAction):
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::updateWebsitePolicies):
+
 2017-03-09  Chris Dumez  <cdumez@apple.com>
 
         [WK2] Prevent app nap for the active tab
index f79c3fb..b54ad10 100644 (file)
@@ -37,8 +37,9 @@ enum class WebsiteAutoplayPolicy {
 struct WebsitePolicies {
 
     bool contentBlockersEnabled { true };
+    bool allowsAutoplayQuirks { false };
     WebsiteAutoplayPolicy autoplayPolicy { WebsiteAutoplayPolicy::Default };
-    
+
     template<class Encoder> void encode(Encoder&) const;
     template<class Decoder> static bool decode(Decoder&, WebsitePolicies&);
 };
@@ -47,6 +48,7 @@ template<class Encoder> void WebsitePolicies::encode(Encoder& encoder) const
 {
     encoder << contentBlockersEnabled;
     encoder.encodeEnum(autoplayPolicy);
+    encoder << allowsAutoplayQuirks;
 }
 
 template<class Decoder> bool WebsitePolicies::decode(Decoder& decoder, WebsitePolicies& result)
@@ -55,6 +57,8 @@ template<class Decoder> bool WebsitePolicies::decode(Decoder& decoder, WebsitePo
         return false;
     if (!decoder.decodeEnum(result.autoplayPolicy))
         return false;
+    if (!decoder.decode(result.allowsAutoplayQuirks))
+        return false;
     return true;
 }
 
index ca74f81..ee23427 100644 (file)
@@ -39,6 +39,9 @@ public:
     bool contentBlockersEnabled() const { return m_websitePolicies.contentBlockersEnabled; }
     void setContentBlockersEnabled(bool enabled) { m_websitePolicies.contentBlockersEnabled = enabled; }
 
+    bool allowsAutoplayQuirks() const { return m_websitePolicies.allowsAutoplayQuirks; }
+    void setAllowsAutoplayQuirks(bool allowsQuirks) { m_websitePolicies.allowsAutoplayQuirks = allowsQuirks; }
+
     WebKit::WebsiteAutoplayPolicy autoplayPolicy() const { return m_websitePolicies.autoplayPolicy; }
     void setAutoplayPolicy(WebKit::WebsiteAutoplayPolicy policy) { m_websitePolicies.autoplayPolicy = policy; }
 
index b9709a6..018a331 100644 (file)
@@ -52,6 +52,16 @@ bool WKWebsitePoliciesGetContentBlockersEnabled(WKWebsitePoliciesRef websitePoli
     return toImpl(websitePolicies)->contentBlockersEnabled();
 }
 
+void WKWebsitePoliciesSetAllowsAutoplayQuirks(WKWebsitePoliciesRef websitePolicies, bool allowsQuirks)
+{
+    toImpl(websitePolicies)->setAllowsAutoplayQuirks(allowsQuirks);
+}
+
+bool WKWebsitePoliciesGetAllowsAutoplayQuirks(WKWebsitePoliciesRef websitePolicies)
+{
+    return toImpl(websitePolicies)->allowsAutoplayQuirks();
+}
+
 WKWebsiteAutoplayPolicy WKWebsitePoliciesGetAutoplayPolicy(WKWebsitePoliciesRef websitePolicies)
 {
     switch (toImpl(websitePolicies)->autoplayPolicy()) {
index 0c8e34f..4938e9f 100644 (file)
@@ -45,6 +45,9 @@ WK_EXPORT WKWebsitePoliciesRef WKWebsitePoliciesCreate();
 WK_EXPORT bool WKWebsitePoliciesGetContentBlockersEnabled(WKWebsitePoliciesRef);
 WK_EXPORT void WKWebsitePoliciesSetContentBlockersEnabled(WKWebsitePoliciesRef, bool);
 
+WK_EXPORT bool WKWebsitePoliciesGetAllowsAutoplayQuirks(WKWebsitePoliciesRef);
+WK_EXPORT void WKWebsitePoliciesSetAllowsAutoplayQuirks(WKWebsitePoliciesRef, bool);
+
 WK_EXPORT WKWebsiteAutoplayPolicy WKWebsitePoliciesGetAutoplayPolicy(WKWebsitePoliciesRef);
 WK_EXPORT void WKWebsitePoliciesSetAutoplayPolicy(WKWebsitePoliciesRef, WKWebsiteAutoplayPolicy);
 
index e10cfc8..d3fb2c4 100644 (file)
@@ -38,6 +38,7 @@ WK_CLASS_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA))
 @interface _WKWebsitePolicies : NSObject
 
 @property (nonatomic) BOOL contentBlockersEnabled;
+@property (nonatomic) BOOL allowsAutoplayQuirks;
 @property (nonatomic) _WKWebsiteAutoplayPolicy autoplayPolicy;
 
 @end
index a621e45..cdac1f9 100644 (file)
     return _websitePolicies->contentBlockersEnabled();
 }
 
+- (void)setAllowsAutoplayQuirks:(BOOL)allowsQuirks
+{
+    _websitePolicies->setAllowsAutoplayQuirks(allowsQuirks);
+}
+
+- (BOOL)allowsAutoplayQuirks
+{
+    return _websitePolicies->allowsAutoplayQuirks();
+}
+
 - (void)setAutoplayPolicy:(_WKWebsiteAutoplayPolicy)policy
 {
     switch (policy) {
index 68779d3..c3733ee 100644 (file)
@@ -817,6 +817,8 @@ void WebFrameLoaderClient::dispatchDecidePolicyForNavigationAction(const Navigat
     if (documentLoader->userContentExtensionsEnabled())
         documentLoader->setUserContentExtensionsEnabled(websitePolicies.contentBlockersEnabled);
 
+    documentLoader->setAllowsAutoplayQuirks(websitePolicies.allowsAutoplayQuirks);
+
     switch (websitePolicies.autoplayPolicy) {
     case WebsiteAutoplayPolicy::Default:
         documentLoader->setAutoplayPolicy(AutoplayPolicy::Default);
index 3a240a1..6df8a9c 100644 (file)
@@ -5460,6 +5460,8 @@ void WebPage::updateWebsitePolicies(const WebsitePolicies& websitePolicies)
     if (!documentLoader)
         return;
 
+    documentLoader->setAllowsAutoplayQuirks(websitePolicies.allowsAutoplayQuirks);
+
     switch (websitePolicies.autoplayPolicy) {
     case WebsiteAutoplayPolicy::Default:
         documentLoader->setAutoplayPolicy(AutoplayPolicy::Default);
index d812e6e..fe6b634 100644 (file)
@@ -1,3 +1,15 @@
+2017-03-08  Matt Rajca  <mrajca@apple.com>
+
+        Let clients control autoplay quirks with website policies.
+        https://bugs.webkit.org/show_bug.cgi?id=169390
+
+        Reviewed by Wenson Hsieh.
+
+        * TestWebKitAPI/Tests/WebKit2/autoplay-check.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/WebsitePolicies.mm:
+        (-[AutoplayPoliciesDelegate _webView:decidePolicyForNavigationAction:decisionHandler:]):
+        (TEST):
+
 2017-03-09  Devin Rousso  <dcrousso+webkit@gmail.com>
 
         Unreviewed, change my status to be a WebKit reviewer
index 3f1a221..4de6247 100644 (file)
                     } catch(e) { }
                 });
             }
+
+            function videoDidPause() {
+                try {
+                    window.webkit.messageHandlers.testHandler.postMessage("on-pause");
+                } catch(e) { }
+            }
         </script>
     </head>
     <body onload="playVideo()">
-        <video id="video" playsinline src="test.mp4" />
+        <video id="video" onpause=videoDidPause() playsinline src="test.mp4" />
     </body>
 </html>
index ab63141..44a15e1 100644 (file)
@@ -28,6 +28,7 @@
 #import "PlatformUtilities.h"
 #import "TestWKWebView.h"
 #import <WebKit/WKPagePrivate.h>
+#import <WebKit/WKPreferencesRefPrivate.h>
 #import <WebKit/WKUserContentControllerPrivate.h>
 #import <WebKit/WKWebViewPrivate.h>
 #import <WebKit/_WKUserContentExtensionStorePrivate.h>
@@ -165,6 +166,7 @@ TEST(WebKit2, WebsitePoliciesContentBlockersEnabled)
 
 @interface AutoplayPoliciesDelegate : NSObject <WKNavigationDelegate, WKUIDelegate>
 @property (nonatomic, copy) _WKWebsiteAutoplayPolicy(^autoplayPolicyForURL)(NSURL *);
+@property (nonatomic) BOOL allowsAutoplayQuirks;
 @end
 
 @implementation AutoplayPoliciesDelegate
@@ -179,6 +181,7 @@ TEST(WebKit2, WebsitePoliciesContentBlockersEnabled)
 - (void)_webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy, _WKWebsitePolicies *))decisionHandler
 {
     _WKWebsitePolicies *websitePolicies = [[[_WKWebsitePolicies alloc] init] autorelease];
+    websitePolicies.allowsAutoplayQuirks = _allowsAutoplayQuirks;
     if (_autoplayPolicyForURL)
         websitePolicies.autoplayPolicy = _autoplayPolicyForURL(navigationAction.request.URL);
     decisionHandler(WKNavigationActionPolicyAllow, websitePolicies);
@@ -437,6 +440,29 @@ TEST(WebKit2, WebsitePoliciesUserNeverPlayedMediaPreventedFromPlaying)
     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"about:blank"]]];
     runUntilReceivesAutoplayEvent(kWKAutoplayEventUserNeverPlayedMediaPreventedFromPlaying);
 }
+
+TEST(WebKit2, WebsitePoliciesAutoplayQuirks)
+{
+    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+
+    auto delegate = adoptNS([[AutoplayPoliciesDelegate alloc] init]);
+    [webView setNavigationDelegate:delegate.get()];
+
+    WKRetainPtr<WKPreferencesRef> preferences(AdoptWK, WKPreferencesCreate());
+    WKPreferencesSetNeedsSiteSpecificQuirks(preferences.get(), true);
+    WKPageGroupSetPreferences(WKPageGetPageGroup([webView _pageForTesting]), preferences.get());
+
+    NSURLRequest *requestWithAudio = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"autoplay-check" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
+
+    [delegate setAllowsAutoplayQuirks:YES];
+    [delegate setAutoplayPolicyForURL:^(NSURL *) {
+        return _WKWebsiteAutoplayPolicyDeny;
+    }];
+    [webView loadRequest:requestWithAudio];
+    [webView waitForMessage:@"did-not-play"];
+    [webView waitForMessage:@"on-pause"];
+}
 #endif
 
 #endif