Title: [214411] trunk
Revision
214411
Author
[email protected]
Date
2017-03-27 02:37:47 -0700 (Mon, 27 Mar 2017)

Log Message

[Modern Media Controls] Improve media documents across macOS, iPhone and iPad
https://bugs.webkit.org/show_bug.cgi?id=169145
<rdar://problem/17048858>

Patch by Antoine Quint <[email protected]> on 2017-03-27
Reviewed by Dean Jackson.

Source/WebCore:

There were a variety of issues with media documents, some longstanding, and some specifically
about modern media controls.

One issue was that fullscreen and picture-in-picture buttons would show for audio media documents,
due to using a <video> element to load the audio file. We now have additional logic in MediaController
to identify if the loaded media is really an audio file, and using this information to hide the
fullscreen and picture-in-picture buttons.

Another issue was that we would inject style in MediaDocument.cpp that was specific to modern media
controls when we could have the modern-media-controls module injected CSS handle this styling. We now
use the injected style in the shadow root to size media documents based on the device characteristics
and ensuring that page styles are overridden.

We also simplify how MediaDocument.cpp sets the source of the media element to simply use the "src"
attribute and not a <source> element.

Finally, we introduce a MediaDocumentController class that is instantiated when we're dealing with
a media document to hide the controls while we determine the type of media we're loading (audio vs.
video) in order to apply the appropriate styling without flashes.

As a result of the new styles applied by the modern-media-controls module, media documents have a
similar behavior on macOS and iPad, where we only enforce a min-width for video allowing them
to play at their natural size otherwise, and enforcing a fixed width for audio. On iPhone however,
we want to always play the media at full width, with some padding in the case of audio.

Tests: media/modern-media-controls/fullscreen-support/fullscreen-support-disabled-video-with-audio-tracks-only.html
       media/modern-media-controls/media-documents/ipad/media-document-audio-ios-sizing.html
       media/modern-media-controls/media-documents/ipad/media-document-video-ios-sizing.html
       media/modern-media-controls/media-documents/media-document-audio-ios-sizing.html
       media/modern-media-controls/media-documents/media-document-audio-mac-sizing.html
       media/modern-media-controls/media-documents/media-document-video-ios-sizing.html
       media/modern-media-controls/media-documents/media-document-video-mac-sizing.html
       media/modern-media-controls/pip-support/pip-support-disabled-video-with-audio-tracks-only.html

* Modules/modern-media-controls/controls/ios-inline-media-controls.css:
(:host(audio) .media-controls.ios.inline > .controls-bar:before,):
(:host(audio) .media-controls.ios.inline > .controls-bar:before): Deleted.
* Modules/modern-media-controls/controls/macos-media-controls.css:
(:host(audio) .media-controls.mac.inline > .controls-bar,):
(:host(audio) .media-controls.mac.inline > .controls-bar > .background-tint,):
(:host(audio) .media-controls.mac.inline > .controls-bar): Deleted.
(:host(audio) .media-controls.mac.inline > .controls-bar > .background-tint): Deleted.
* Modules/modern-media-controls/controls/media-document.css: Added.
(:host(.media-document)):
(:host(.media-document.ready)):
(:host(.media-document.audio.mac)):
(:host(.media-document.audio.ipad)):
(:host(.media-document.audio.iphone)):
(:host(.media-document.video.mac)):
(:host(.media-document.video.ipad)):
(:host(.media-document.video.iphone)):
* Modules/modern-media-controls/js-files:
* Modules/modern-media-controls/media/fullscreen-support.js:
(FullscreenSupport.prototype.syncControl):
(FullscreenSupport):
* Modules/modern-media-controls/media/media-controller.js:
(MediaController):
(MediaController.prototype.get isAudio):
* Modules/modern-media-controls/media/media-document-controller.js: Added.
(MediaDocumentController):
(MediaDocumentController.prototype.handleEvent):
(MediaDocumentController.prototype._mediaDocumentHasMetadata):
(MediaDocumentController.prototype._mediaDocumentHasSize):
* Modules/modern-media-controls/media/pip-support.js:
(PiPSupport.prototype.syncControl):
(PiPSupport):
* html/MediaDocument.cpp:
(WebCore::MediaDocumentParser::createDocumentStructure):

LayoutTests:

We add new tests for media documents and related features that cover the following cases:

    - checking <video> with only audio tracks does not show the fullscreen button
    - checking <video> with only audio tracks does not show the picture-in-picture button
    - checking the size used in media documents for audio and video across macOS, iPhone and iPad

* media/modern-media-controls/fullscreen-support/fullscreen-support-disabled-video-with-audio-tracks-only-expected.txt: Added.
* media/modern-media-controls/fullscreen-support/fullscreen-support-disabled-video-with-audio-tracks-only.html: Added.
* media/modern-media-controls/media-documents/ipad/media-document-audio-ios-sizing-expected.txt: Added.
* media/modern-media-controls/media-documents/ipad/media-document-audio-ios-sizing.html: Added.
* media/modern-media-controls/media-documents/ipad/media-document-video-ios-sizing-expected.txt: Added.
* media/modern-media-controls/media-documents/ipad/media-document-video-ios-sizing.html: Added.
* media/modern-media-controls/media-documents/media-document-audio-ios-sizing-expected.txt: Added.
* media/modern-media-controls/media-documents/media-document-audio-ios-sizing.html: Added.
* media/modern-media-controls/media-documents/media-document-audio-mac-sizing-expected.txt: Added.
* media/modern-media-controls/media-documents/media-document-audio-mac-sizing.html: Added.
* media/modern-media-controls/media-documents/media-document-video-ios-sizing-expected.txt: Added.
* media/modern-media-controls/media-documents/media-document-video-ios-sizing.html: Added.
* media/modern-media-controls/media-documents/media-document-video-mac-sizing-expected.txt: Added.
* media/modern-media-controls/media-documents/media-document-video-mac-sizing.html: Added.
* media/modern-media-controls/pip-support/pip-support-disabled-video-with-audio-tracks-only-expected.txt: Added.
* media/modern-media-controls/pip-support/pip-support-disabled-video-with-audio-tracks-only.html: Added.
* platform/ios-simulator/TestExpectations:
* platform/mac/TestExpectations:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (214410 => 214411)


--- trunk/LayoutTests/ChangeLog	2017-03-27 04:17:52 UTC (rev 214410)
+++ trunk/LayoutTests/ChangeLog	2017-03-27 09:37:47 UTC (rev 214411)
@@ -1,3 +1,36 @@
+2017-03-27  Antoine Quint  <[email protected]>
+
+        [Modern Media Controls] Improve media documents across macOS, iPhone and iPad
+        https://bugs.webkit.org/show_bug.cgi?id=169145
+        <rdar://problem/17048858>
+
+        Reviewed by Dean Jackson.
+
+        We add new tests for media documents and related features that cover the following cases:
+        
+            - checking <video> with only audio tracks does not show the fullscreen button
+            - checking <video> with only audio tracks does not show the picture-in-picture button
+            - checking the size used in media documents for audio and video across macOS, iPhone and iPad
+
+        * media/modern-media-controls/fullscreen-support/fullscreen-support-disabled-video-with-audio-tracks-only-expected.txt: Added.
+        * media/modern-media-controls/fullscreen-support/fullscreen-support-disabled-video-with-audio-tracks-only.html: Added.
+        * media/modern-media-controls/media-documents/ipad/media-document-audio-ios-sizing-expected.txt: Added.
+        * media/modern-media-controls/media-documents/ipad/media-document-audio-ios-sizing.html: Added.
+        * media/modern-media-controls/media-documents/ipad/media-document-video-ios-sizing-expected.txt: Added.
+        * media/modern-media-controls/media-documents/ipad/media-document-video-ios-sizing.html: Added.
+        * media/modern-media-controls/media-documents/media-document-audio-ios-sizing-expected.txt: Added.
+        * media/modern-media-controls/media-documents/media-document-audio-ios-sizing.html: Added.
+        * media/modern-media-controls/media-documents/media-document-audio-mac-sizing-expected.txt: Added.
+        * media/modern-media-controls/media-documents/media-document-audio-mac-sizing.html: Added.
+        * media/modern-media-controls/media-documents/media-document-video-ios-sizing-expected.txt: Added.
+        * media/modern-media-controls/media-documents/media-document-video-ios-sizing.html: Added.
+        * media/modern-media-controls/media-documents/media-document-video-mac-sizing-expected.txt: Added.
+        * media/modern-media-controls/media-documents/media-document-video-mac-sizing.html: Added.
+        * media/modern-media-controls/pip-support/pip-support-disabled-video-with-audio-tracks-only-expected.txt: Added.
+        * media/modern-media-controls/pip-support/pip-support-disabled-video-with-audio-tracks-only.html: Added.
+        * platform/ios-simulator/TestExpectations:
+        * platform/mac/TestExpectations:
+
 2017-03-25  Aaron Chu  <[email protected]>
 
         AX: Media controls are unlabeled

Added: trunk/LayoutTests/media/modern-media-controls/fullscreen-support/fullscreen-support-disabled-video-with-audio-tracks-only-expected.txt (0 => 214411)


--- trunk/LayoutTests/media/modern-media-controls/fullscreen-support/fullscreen-support-disabled-video-with-audio-tracks-only-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/fullscreen-support/fullscreen-support-disabled-video-with-audio-tracks-only-expected.txt	2017-03-27 09:37:47 UTC (rev 214411)
@@ -0,0 +1,14 @@
+Testing that the fullscreen button is disabled for <video> with an audio resource.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Once media loads its metadata the fullscreen button should become disabled
+Obtained loadedmetadata event
+PASS mediaController.isAudio is true
+PASS mediaController.controls.fullscreenButton.enabled is false
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/media/modern-media-controls/fullscreen-support/fullscreen-support-disabled-video-with-audio-tracks-only.html (0 => 214411)


--- trunk/LayoutTests/media/modern-media-controls/fullscreen-support/fullscreen-support-disabled-video-with-audio-tracks-only.html	                        (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/fullscreen-support/fullscreen-support-disabled-video-with-audio-tracks-only.html	2017-03-27 09:37:47 UTC (rev 214411)
@@ -0,0 +1,44 @@
+<script src=""
+<script src="" type="text/_javascript_"></script>
+<body>
+<style type="text/css" media="screen">
+    
+    video, #host {
+        position: absolute;
+        top: 0;
+        left: 0;
+    }
+
+    video {
+        width: 800px;
+        height: 240px;
+    }
+    
+</style>
+<video src="" controls autoplay></video>
+<div id="host"></div>
+<script type="text/_javascript_">
+
+window.jsTestIsAsync = true;
+
+description("Testing that the fullscreen button is disabled for &lt;video> with an audio resource.");
+
+const container = document.querySelector("div#host");
+const media = document.querySelector("video");
+const mediaController = createControls(container, media, null);
+
+debug("Once media loads its metadata the fullscreen button should become disabled");
+media.addEventListener("loadedmetadata", () => {
+    debug("Obtained loadedmetadata event");
+    shouldBeTrue("mediaController.isAudio");
+    shouldBeFalse("mediaController.controls.fullscreenButton.enabled");
+    
+    debug("");
+    media.remove();
+    container.remove();
+    finishJSTest();
+});
+
+</script>
+<script src=""
+</body>

Added: trunk/LayoutTests/media/modern-media-controls/media-documents/ipad/media-document-audio-ios-sizing-expected.txt (0 => 214411)


--- trunk/LayoutTests/media/modern-media-controls/media-documents/ipad/media-document-audio-ios-sizing-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/media-documents/ipad/media-document-audio-ios-sizing-expected.txt	2017-03-27 09:37:47 UTC (rev 214411)
@@ -0,0 +1,12 @@
+Testing the size of the media element in an audio media document on iOS.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS getComputedStyle(media).width became "650px"
+PASS getComputedStyle(media).height is "50px"
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/media/modern-media-controls/media-documents/ipad/media-document-audio-ios-sizing.html (0 => 214411)


--- trunk/LayoutTests/media/modern-media-controls/media-documents/ipad/media-document-audio-ios-sizing.html	                        (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/media-documents/ipad/media-document-audio-ios-sizing.html	2017-03-27 09:37:47 UTC (rev 214411)
@@ -0,0 +1,34 @@
+<script src=""
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<body>
+<iframe src="" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></iframe>
+<script type="text/_javascript_">
+
+description("Testing the size of the media element in an audio media document on iOS.");
+
+window.jsTestIsAsync = true;
+
+let media;
+
+(function runTestIfReady() {
+    const iframe = document.querySelector("iframe");
+    media = iframe.contentDocument.querySelector("video");
+
+    if (!media) {
+        setTimeout(runTestIfReady);
+        return;
+    }
+
+    shouldBecomeEqualToString("getComputedStyle(media).width", "650px", () => {
+        shouldBeEqualToString("getComputedStyle(media).height", "50px");
+
+        debug("");
+        iframe.remove();
+        finishJSTest();
+    });
+
+})();
+
+</script>
+<script src=""
+</body>

Added: trunk/LayoutTests/media/modern-media-controls/media-documents/ipad/media-document-video-ios-sizing-expected.txt (0 => 214411)


--- trunk/LayoutTests/media/modern-media-controls/media-documents/ipad/media-document-video-ios-sizing-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/media-documents/ipad/media-document-video-ios-sizing-expected.txt	2017-03-27 09:37:47 UTC (rev 214411)
@@ -0,0 +1,12 @@
+Testing the size of the media element in a video media document on iOS.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS getComputedStyle(media).width became "700px"
+PASS getComputedStyle(media).height is "525px"
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/media/modern-media-controls/media-documents/ipad/media-document-video-ios-sizing.html (0 => 214411)


--- trunk/LayoutTests/media/modern-media-controls/media-documents/ipad/media-document-video-ios-sizing.html	                        (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/media-documents/ipad/media-document-video-ios-sizing.html	2017-03-27 09:37:47 UTC (rev 214411)
@@ -0,0 +1,34 @@
+<script src=""
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<body>
+<iframe src="" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></iframe>
+<script type="text/_javascript_">
+
+description("Testing the size of the media element in a video media document on iOS.");
+
+window.jsTestIsAsync = true;
+
+let media;
+
+(function runTestIfReady() {
+    const iframe = document.querySelector("iframe");
+    media = iframe.contentDocument.querySelector("video");
+
+    if (!media) {
+        setTimeout(runTestIfReady);
+        return;
+    }
+
+    shouldBecomeEqualToString("getComputedStyle(media).width", "700px", () => {
+        shouldBeEqualToString("getComputedStyle(media).height", "525px");
+
+        debug("");
+        iframe.remove();
+        finishJSTest();
+    });
+
+})();
+
+</script>
+<script src=""
+</body>

Added: trunk/LayoutTests/media/modern-media-controls/media-documents/media-document-audio-ios-sizing-expected.txt (0 => 214411)


--- trunk/LayoutTests/media/modern-media-controls/media-documents/media-document-audio-ios-sizing-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/media-documents/media-document-audio-ios-sizing-expected.txt	2017-03-27 09:37:47 UTC (rev 214411)
@@ -0,0 +1,12 @@
+Testing the size of the media element in an audio media document on iOS.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS getComputedStyle(media).width became "320px"
+PASS getComputedStyle(media).height is "50px"
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/media/modern-media-controls/media-documents/media-document-audio-ios-sizing.html (0 => 214411)


--- trunk/LayoutTests/media/modern-media-controls/media-documents/media-document-audio-ios-sizing.html	                        (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/media-documents/media-document-audio-ios-sizing.html	2017-03-27 09:37:47 UTC (rev 214411)
@@ -0,0 +1,35 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true ] -->
+<script src=""
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<body>
+<iframe src="" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></iframe>
+<script type="text/_javascript_">
+
+description("Testing the size of the media element in an audio media document on iOS.");
+
+window.jsTestIsAsync = true;
+
+let media;
+
+(function runTestIfReady() {
+    const iframe = document.querySelector("iframe");
+    media = iframe.contentDocument.querySelector("video");
+
+    if (!media) {
+        setTimeout(runTestIfReady);
+        return;
+    }
+
+    shouldBecomeEqualToString("getComputedStyle(media).width", "320px", () => {
+        shouldBeEqualToString("getComputedStyle(media).height", "50px");
+
+        debug("");
+        iframe.remove();
+        finishJSTest();
+    });
+
+})();
+
+</script>
+<script src=""
+</body>

Added: trunk/LayoutTests/media/modern-media-controls/media-documents/media-document-audio-mac-sizing-expected.txt (0 => 214411)


--- trunk/LayoutTests/media/modern-media-controls/media-documents/media-document-audio-mac-sizing-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/media-documents/media-document-audio-mac-sizing-expected.txt	2017-03-27 09:37:47 UTC (rev 214411)
@@ -0,0 +1,12 @@
+Testing the size of the media element in an audio media document on macOS.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS getComputedStyle(media).width became "650px"
+PASS getComputedStyle(media).height is "25px"
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/media/modern-media-controls/media-documents/media-document-audio-mac-sizing.html (0 => 214411)


--- trunk/LayoutTests/media/modern-media-controls/media-documents/media-document-audio-mac-sizing.html	                        (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/media-documents/media-document-audio-mac-sizing.html	2017-03-27 09:37:47 UTC (rev 214411)
@@ -0,0 +1,33 @@
+<script src=""
+<body>
+<iframe src="" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></iframe>
+<script type="text/_javascript_">
+
+description("Testing the size of the media element in an audio media document on macOS.");
+
+window.jsTestIsAsync = true;
+
+let media;
+
+(function runTestIfReady() {
+    const iframe = document.querySelector("iframe");
+    media = iframe.contentDocument.querySelector("video");
+
+    if (!media) {
+        setTimeout(runTestIfReady);
+        return;
+    }
+
+    shouldBecomeEqualToString("getComputedStyle(media).width", "650px", () => {
+        shouldBeEqualToString("getComputedStyle(media).height", "25px");
+
+        debug("");
+        iframe.remove();
+        finishJSTest();
+    });
+
+})();
+
+</script>
+<script src=""
+</body>

Added: trunk/LayoutTests/media/modern-media-controls/media-documents/media-document-video-ios-sizing-expected.txt (0 => 214411)


--- trunk/LayoutTests/media/modern-media-controls/media-documents/media-document-video-ios-sizing-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/media-documents/media-document-video-ios-sizing-expected.txt	2017-03-27 09:37:47 UTC (rev 214411)
@@ -0,0 +1,12 @@
+Testing the size of the media element in a video media document on iOS.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS getComputedStyle(media).height became "240px"
+PASS getComputedStyle(media).width is "320px"
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/media/modern-media-controls/media-documents/media-document-video-ios-sizing.html (0 => 214411)


--- trunk/LayoutTests/media/modern-media-controls/media-documents/media-document-video-ios-sizing.html	                        (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/media-documents/media-document-video-ios-sizing.html	2017-03-27 09:37:47 UTC (rev 214411)
@@ -0,0 +1,35 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true ] -->
+<script src=""
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<body>
+<iframe src="" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></iframe>
+<script type="text/_javascript_">
+
+description("Testing the size of the media element in a video media document on iOS.");
+
+window.jsTestIsAsync = true;
+
+let media;
+
+(function runTestIfReady() {
+    const iframe = document.querySelector("iframe");
+    media = iframe.contentDocument.querySelector("video");
+
+    if (!media) {
+        setTimeout(runTestIfReady);
+        return;
+    }
+
+    shouldBecomeEqualToString("getComputedStyle(media).height", "240px", () => {
+        shouldBeEqualToString("getComputedStyle(media).width", "320px");
+
+        debug("");
+        iframe.remove();
+        finishJSTest();
+    });
+
+})();
+
+</script>
+<script src=""
+</body>

Added: trunk/LayoutTests/media/modern-media-controls/media-documents/media-document-video-mac-sizing-expected.txt (0 => 214411)


--- trunk/LayoutTests/media/modern-media-controls/media-documents/media-document-video-mac-sizing-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/media-documents/media-document-video-mac-sizing-expected.txt	2017-03-27 09:37:47 UTC (rev 214411)
@@ -0,0 +1,12 @@
+Testing the size of the media element in a video media document on macOS.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS getComputedStyle(media).width became "700px"
+PASS getComputedStyle(media).height is "525px"
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/media/modern-media-controls/media-documents/media-document-video-mac-sizing.html (0 => 214411)


--- trunk/LayoutTests/media/modern-media-controls/media-documents/media-document-video-mac-sizing.html	                        (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/media-documents/media-document-video-mac-sizing.html	2017-03-27 09:37:47 UTC (rev 214411)
@@ -0,0 +1,33 @@
+<script src=""
+<body>
+<iframe src="" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></iframe>
+<script type="text/_javascript_">
+
+description("Testing the size of the media element in a video media document on macOS.");
+
+window.jsTestIsAsync = true;
+
+let media;
+
+(function runTestIfReady() {
+    const iframe = document.querySelector("iframe");
+    media = iframe.contentDocument.querySelector("video");
+
+    if (!media) {
+        setTimeout(runTestIfReady);
+        return;
+    }
+
+    shouldBecomeEqualToString("getComputedStyle(media).width", "700px", () => {
+        shouldBeEqualToString("getComputedStyle(media).height", "525px");
+
+        debug("");
+        iframe.remove();
+        finishJSTest();
+    });
+
+})();
+
+</script>
+<script src=""
+</body>

Added: trunk/LayoutTests/media/modern-media-controls/pip-support/pip-support-disabled-video-with-audio-tracks-only-expected.txt (0 => 214411)


--- trunk/LayoutTests/media/modern-media-controls/pip-support/pip-support-disabled-video-with-audio-tracks-only-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/pip-support/pip-support-disabled-video-with-audio-tracks-only-expected.txt	2017-03-27 09:37:47 UTC (rev 214411)
@@ -0,0 +1,14 @@
+Testing that the picture-in-picture button is disabled for <video> with an audio resource.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Once media loads its metadata the picture-in-picture button should become disabled
+Obtained loadedmetadata event
+PASS mediaController.isAudio is true
+PASS mediaController.controls.pipButton.enabled is false
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/media/modern-media-controls/pip-support/pip-support-disabled-video-with-audio-tracks-only.html (0 => 214411)


--- trunk/LayoutTests/media/modern-media-controls/pip-support/pip-support-disabled-video-with-audio-tracks-only.html	                        (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/pip-support/pip-support-disabled-video-with-audio-tracks-only.html	2017-03-27 09:37:47 UTC (rev 214411)
@@ -0,0 +1,44 @@
+<script src=""
+<script src="" type="text/_javascript_"></script>
+<body>
+<style type="text/css" media="screen">
+    
+    video, #host {
+        position: absolute;
+        top: 0;
+        left: 0;
+    }
+
+    video {
+        width: 800px;
+        height: 240px;
+    }
+    
+</style>
+<video src="" controls autoplay></video>
+<div id="host"></div>
+<script type="text/_javascript_">
+
+window.jsTestIsAsync = true;
+
+description("Testing that the picture-in-picture button is disabled for &lt;video> with an audio resource.");
+
+const container = document.querySelector("div#host");
+const media = document.querySelector("video");
+const mediaController = createControls(container, media, null);
+
+debug("Once media loads its metadata the picture-in-picture button should become disabled");
+media.addEventListener("loadedmetadata", () => {
+    debug("Obtained loadedmetadata event");
+    shouldBeTrue("mediaController.isAudio");
+    shouldBeFalse("mediaController.controls.pipButton.enabled");
+    
+    debug("");
+    media.remove();
+    container.remove();
+    finishJSTest();
+});
+
+</script>
+<script src=""
+</body>

Modified: trunk/LayoutTests/platform/ios-simulator/TestExpectations (214410 => 214411)


--- trunk/LayoutTests/platform/ios-simulator/TestExpectations	2017-03-27 04:17:52 UTC (rev 214410)
+++ trunk/LayoutTests/platform/ios-simulator/TestExpectations	2017-03-27 09:37:47 UTC (rev 214411)
@@ -2840,6 +2840,8 @@
 media/modern-media-controls/placard-support/placard-support-pip.html [ Skip ]
 media/modern-media-controls/scrubber-support/scrubber-support-drag.html [ Skip ]
 media/modern-media-controls/scrubber-support/ipad/scrubber-support-drag.html [ Skip ]
+media/modern-media-controls/media-documents/media-document-audio-mac-sizing.html [ Skip ]
+media/modern-media-controls/media-documents/media-document-video-mac-sizing.html [ Skip ]
 
 # These tests use uiController and need to be skipped in open-source
 media/modern-media-controls/placard-support/ipad/placard-support-pip.html [ Skip ]

Modified: trunk/LayoutTests/platform/mac/TestExpectations (214410 => 214411)


--- trunk/LayoutTests/platform/mac/TestExpectations	2017-03-27 04:17:52 UTC (rev 214410)
+++ trunk/LayoutTests/platform/mac/TestExpectations	2017-03-27 09:37:47 UTC (rev 214411)
@@ -1471,6 +1471,10 @@
 media/modern-media-controls/media-controller/media-controller-ios-only-enable-tap-gesture-recognizer-with-fades-when-idle.html [ Skip ]
 media/modern-media-controls/media-controller/media-controller-ios-do-not-hide-controls-when-tapping-button.html [ Skip ]
 media/modern-media-controls/media-controller/media-controller-tight-padding.html [ Skip ]
+media/modern-media-controls/media-documents/media-document-audio-ios-sizing.html [ Skip ]
+media/modern-media-controls/media-documents/media-document-video-ios-sizing.html [ Skip ]
+media/modern-media-controls/media-documents/ipad/media-document-audio-ios-sizing.html [ Skip ]
+media/modern-media-controls/media-documents/ipad/media-document-video-ios-sizing.html [ Skip ]
 media/modern-media-controls/audio/audio-controls-styles.html [ Skip ]
 
 webkit.org/b/169118 [ Debug ] media/modern-media-controls/fullscreen-support/fullscreen-support-click.html [ Pass Timeout ]

Modified: trunk/Source/WebCore/ChangeLog (214410 => 214411)


--- trunk/Source/WebCore/ChangeLog	2017-03-27 04:17:52 UTC (rev 214410)
+++ trunk/Source/WebCore/ChangeLog	2017-03-27 09:37:47 UTC (rev 214411)
@@ -1,3 +1,80 @@
+2017-03-27  Antoine Quint  <[email protected]>
+
+        [Modern Media Controls] Improve media documents across macOS, iPhone and iPad
+        https://bugs.webkit.org/show_bug.cgi?id=169145
+        <rdar://problem/17048858>
+
+        Reviewed by Dean Jackson.
+
+        There were a variety of issues with media documents, some longstanding, and some specifically
+        about modern media controls.
+
+        One issue was that fullscreen and picture-in-picture buttons would show for audio media documents,
+        due to using a <video> element to load the audio file. We now have additional logic in MediaController
+        to identify if the loaded media is really an audio file, and using this information to hide the
+        fullscreen and picture-in-picture buttons.
+
+        Another issue was that we would inject style in MediaDocument.cpp that was specific to modern media
+        controls when we could have the modern-media-controls module injected CSS handle this styling. We now
+        use the injected style in the shadow root to size media documents based on the device characteristics
+        and ensuring that page styles are overridden.
+
+        We also simplify how MediaDocument.cpp sets the source of the media element to simply use the "src"
+        attribute and not a <source> element.
+
+        Finally, we introduce a MediaDocumentController class that is instantiated when we're dealing with
+        a media document to hide the controls while we determine the type of media we're loading (audio vs.
+        video) in order to apply the appropriate styling without flashes.
+
+        As a result of the new styles applied by the modern-media-controls module, media documents have a
+        similar behavior on macOS and iPad, where we only enforce a min-width for video allowing them
+        to play at their natural size otherwise, and enforcing a fixed width for audio. On iPhone however,
+        we want to always play the media at full width, with some padding in the case of audio.
+
+        Tests: media/modern-media-controls/fullscreen-support/fullscreen-support-disabled-video-with-audio-tracks-only.html
+               media/modern-media-controls/media-documents/ipad/media-document-audio-ios-sizing.html
+               media/modern-media-controls/media-documents/ipad/media-document-video-ios-sizing.html
+               media/modern-media-controls/media-documents/media-document-audio-ios-sizing.html
+               media/modern-media-controls/media-documents/media-document-audio-mac-sizing.html
+               media/modern-media-controls/media-documents/media-document-video-ios-sizing.html
+               media/modern-media-controls/media-documents/media-document-video-mac-sizing.html
+               media/modern-media-controls/pip-support/pip-support-disabled-video-with-audio-tracks-only.html
+
+        * Modules/modern-media-controls/controls/ios-inline-media-controls.css:
+        (:host(audio) .media-controls.ios.inline > .controls-bar:before,):
+        (:host(audio) .media-controls.ios.inline > .controls-bar:before): Deleted.
+        * Modules/modern-media-controls/controls/macos-media-controls.css:
+        (:host(audio) .media-controls.mac.inline > .controls-bar,):
+        (:host(audio) .media-controls.mac.inline > .controls-bar > .background-tint,):
+        (:host(audio) .media-controls.mac.inline > .controls-bar): Deleted.
+        (:host(audio) .media-controls.mac.inline > .controls-bar > .background-tint): Deleted.
+        * Modules/modern-media-controls/controls/media-document.css: Added.
+        (:host(.media-document)):
+        (:host(.media-document.ready)):
+        (:host(.media-document.audio.mac)):
+        (:host(.media-document.audio.ipad)):
+        (:host(.media-document.audio.iphone)):
+        (:host(.media-document.video.mac)):
+        (:host(.media-document.video.ipad)):
+        (:host(.media-document.video.iphone)):
+        * Modules/modern-media-controls/js-files:
+        * Modules/modern-media-controls/media/fullscreen-support.js:
+        (FullscreenSupport.prototype.syncControl):
+        (FullscreenSupport):
+        * Modules/modern-media-controls/media/media-controller.js:
+        (MediaController):
+        (MediaController.prototype.get isAudio):
+        * Modules/modern-media-controls/media/media-document-controller.js: Added.
+        (MediaDocumentController):
+        (MediaDocumentController.prototype.handleEvent):
+        (MediaDocumentController.prototype._mediaDocumentHasMetadata):
+        (MediaDocumentController.prototype._mediaDocumentHasSize):
+        * Modules/modern-media-controls/media/pip-support.js:
+        (PiPSupport.prototype.syncControl):
+        (PiPSupport):
+        * html/MediaDocument.cpp:
+        (WebCore::MediaDocumentParser::createDocumentStructure):
+
 2017-03-25  Chris Dumez  <[email protected]>
 
         REGRESSION(r214195): zillow.com header video doesn't resume when switching to another tab and back

Modified: trunk/Source/WebCore/Modules/modern-media-controls/controls/ios-inline-media-controls.css (214410 => 214411)


--- trunk/Source/WebCore/Modules/modern-media-controls/controls/ios-inline-media-controls.css	2017-03-27 04:17:52 UTC (rev 214410)
+++ trunk/Source/WebCore/Modules/modern-media-controls/controls/ios-inline-media-controls.css	2017-03-27 09:37:47 UTC (rev 214411)
@@ -43,7 +43,8 @@
     will-change: transform;
 }
 
-:host(audio) .media-controls.ios.inline > .controls-bar:before {
+:host(audio) .media-controls.ios.inline > .controls-bar:before,
+:host(.media-document.audio) .media-controls.ios.inline > .controls-bar:before {
     -webkit-appearance: none;
     background-color: rgb(212, 212, 212);
 }

Modified: trunk/Source/WebCore/Modules/modern-media-controls/controls/macos-media-controls.css (214410 => 214411)


--- trunk/Source/WebCore/Modules/modern-media-controls/controls/macos-media-controls.css	2017-03-27 04:17:52 UTC (rev 214410)
+++ trunk/Source/WebCore/Modules/modern-media-controls/controls/macos-media-controls.css	2017-03-27 09:37:47 UTC (rev 214411)
@@ -50,10 +50,12 @@
     -webkit-appearance: none !important;
 }
 
-:host(audio) .media-controls.mac.inline > .controls-bar {
+:host(audio) .media-controls.mac.inline > .controls-bar,
+:host(.media-document.audio) .media-controls.mac.inline > .controls-bar {
     background-color: rgb(41, 41, 41);
 }
 
-:host(audio) .media-controls.mac.inline > .controls-bar > .background-tint {
+:host(audio) .media-controls.mac.inline > .controls-bar > .background-tint,
+:host(.media-document.audio) .media-controls.mac.inline > .controls-bar > .background-tint {
     display: none;
 }

Copied: trunk/Source/WebCore/Modules/modern-media-controls/controls/media-document.css (from rev 214410, trunk/Source/WebCore/Modules/modern-media-controls/controls/macos-media-controls.css) (0 => 214411)


--- trunk/Source/WebCore/Modules/modern-media-controls/controls/media-document.css	                        (rev 0)
+++ trunk/Source/WebCore/Modules/modern-media-controls/controls/media-document.css	2017-03-27 09:37:47 UTC (rev 214411)
@@ -0,0 +1,65 @@
+/*
+ * 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. ``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
+ * 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.
+ */
+
+:host(.media-document) {
+    visibility: hidden !important;
+    max-width: 100% !important;
+    min-height: 50px !important;
+}
+
+:host(.media-document.ready) {
+    visibility: visible !important;
+}
+
+/* Audio */
+
+:host(.media-document.audio.mac) {
+    width: 650px !important;
+    min-height: 25px !important;
+}
+
+:host(.media-document.audio.ipad) {
+    width: 650px !important;
+}
+
+:host(.media-document.audio.iphone) {
+    padding: 0 10px;
+    width: 100% !important;
+    box-sizing: border-box;
+}
+
+/* Video */
+
+:host(.media-document.video.mac) {
+    min-width: 700px !important;
+}
+
+:host(.media-document.video.ipad) {
+    min-width: 700px !important;
+}
+
+:host(.media-document.video.iphone) {
+    width: 100% !important;
+}

Modified: trunk/Source/WebCore/Modules/modern-media-controls/js-files (214410 => 214411)


--- trunk/Source/WebCore/Modules/modern-media-controls/js-files	2017-03-27 04:17:52 UTC (rev 214410)
+++ trunk/Source/WebCore/Modules/modern-media-controls/js-files	2017-03-27 09:37:47 UTC (rev 214411)
@@ -61,5 +61,6 @@
 media/volume-down-support.js
 media/volume-support.js
 media/volume-up-support.js
+media/media-document-controller.js
 media/media-controller.js
 

Modified: trunk/Source/WebCore/Modules/modern-media-controls/media/fullscreen-support.js (214410 => 214411)


--- trunk/Source/WebCore/Modules/modern-media-controls/media/fullscreen-support.js	2017-03-27 04:17:52 UTC (rev 214410)
+++ trunk/Source/WebCore/Modules/modern-media-controls/media/fullscreen-support.js	2017-03-27 09:37:47 UTC (rev 214411)
@@ -69,7 +69,7 @@
     {
         const control = this.control;
         const media = this.mediaController.media;
-        control.enabled = media.webkitSupportsFullscreen && media.videoTracks.length > 0;
+        control.enabled = !this.mediaController.isAudio && media.webkitSupportsFullscreen;
         control.isFullScreen = media.webkitDisplayingFullscreen;
     }
 

Modified: trunk/Source/WebCore/Modules/modern-media-controls/media/media-controller.js (214410 => 214411)


--- trunk/Source/WebCore/Modules/modern-media-controls/media/media-controller.js	2017-03-27 04:17:52 UTC (rev 214410)
+++ trunk/Source/WebCore/Modules/modern-media-controls/media/media-controller.js	2017-03-27 09:37:47 UTC (rev 214411)
@@ -41,6 +41,8 @@
         if (host) {
             host.controlsDependOnPageScaleFactor = this.layoutTraits & LayoutTraits.iOS;
             this.container.appendChild(host.textTrackContainer);
+            if (host.isInMediaDocument)
+                this.mediaDocumentController = new MediaDocumentController(this);
         }
 
         this._updateControlsIfNeeded();
@@ -61,7 +63,15 @@
 
     get isAudio()
     {
-        return this.media instanceof HTMLAudioElement || (this.media.readyState >= HTMLMediaElement.HAVE_METADATA && this.media.videoWidth === 0);
+        if (this.media instanceof HTMLAudioElement)
+            return true;
+
+        if (this.media.readyState < HTMLMediaElement.HAVE_METADATA)
+            return false;
+
+        const isLiveBroadcast = this.media.duration === Number.POSITIVE_INFINITY;
+        const hasVideoTracks = this.media.videoWidth != 0;
+        return !isLiveBroadcast && !hasVideoTracks;
     }
 
     get layoutTraits()

Copied: trunk/Source/WebCore/Modules/modern-media-controls/media/media-document-controller.js (from rev 214410, trunk/Source/WebCore/Modules/modern-media-controls/media/fullscreen-support.js) (0 => 214411)


--- trunk/Source/WebCore/Modules/modern-media-controls/media/media-document-controller.js	                        (rev 0)
+++ trunk/Source/WebCore/Modules/modern-media-controls/media/media-document-controller.js	2017-03-27 09:37:47 UTC (rev 214411)
@@ -0,0 +1,75 @@
+/*
+ * 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. ``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
+ * 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.
+ */
+
+class MediaDocumentController
+{
+
+    constructor(mediaController)
+    {
+        this.mediaController = mediaController;
+
+        const media = mediaController.media;
+        media.classList.add("media-document");
+
+        if (media.readyState >= HTMLMediaElement.HAVE_METADATA)
+            this._mediaDocumentHasMetadata();
+        else
+            media.addEventListener("loadedmetadata", this);
+    }
+
+    // Protected
+
+    handleEvent(event)
+    {
+        event.currentTarget.removeEventListener(event.type, this);
+
+        if (event.type === "loadedmetadata")
+            this._mediaDocumentHasMetadata();
+        else if (event.type === "resize")
+            this._mediaDocumentHasSize();
+    }
+
+    // Private
+
+    _mediaDocumentHasMetadata()
+    {
+        window.requestAnimationFrame(() => {
+            const media = this.mediaController.media;
+            media.classList.add(this.mediaController.isAudio ? "audio" : "video");
+            media.classList.add(window.navigator.platform === "MacIntel" ? "mac" : window.navigator.platform);
+
+            if (this.mediaController.isAudio)
+                this._mediaDocumentHasSize();
+            else
+                this.mediaController.shadowRoot.addEventListener("resize", this);
+        });
+    }
+
+    _mediaDocumentHasSize()
+    {
+        window.requestAnimationFrame(() => this.mediaController.media.classList.add("ready"));
+    }
+
+}

Modified: trunk/Source/WebCore/Modules/modern-media-controls/media/pip-support.js (214410 => 214411)


--- trunk/Source/WebCore/Modules/modern-media-controls/media/pip-support.js	2017-03-27 04:17:52 UTC (rev 214410)
+++ trunk/Source/WebCore/Modules/modern-media-controls/media/pip-support.js	2017-03-27 09:37:47 UTC (rev 214411)
@@ -56,7 +56,7 @@
     {
         const media = this.mediaController.media;
         if (media.webkitSupportsPresentationMode)
-            this.control.enabled = media instanceof HTMLVideoElement && media.webkitSupportsPresentationMode(PiPMode) && !media.webkitCurrentPlaybackTargetIsWireless;
+            this.control.enabled = !this.mediaController.isAudio && media.webkitSupportsPresentationMode(PiPMode) && !media.webkitCurrentPlaybackTargetIsWireless;
         else
             this.control.enabled = false;
     }

Modified: trunk/Source/WebCore/html/MediaDocument.cpp (214410 => 214411)


--- trunk/Source/WebCore/html/MediaDocument.cpp	2017-03-27 04:17:52 UTC (rev 214410)
+++ trunk/Source/WebCore/html/MediaDocument.cpp	2017-03-27 09:37:47 UTC (rev 214411)
@@ -104,13 +104,6 @@
 #endif
 
     auto body = HTMLBodyElement::create(document);
-    if (RuntimeEnabledFeatures::sharedFeatures().modernMediaControlsEnabled()) {
-        StringBuilder bodyStyle;
-        bodyStyle.appendLiteral("margin: 0; padding: 0;");
-        bodyStyle.appendLiteral("background-color: rgb(38, 38, 38);");
-        bodyStyle.appendLiteral("display: flex; justify-content: center; align-items: center;");
-        body->setAttribute(styleAttr, bodyStyle.toString());
-    }
     rootElement->appendChild(body);
 
     auto videoElement = HTMLVideoElement::create(document);
@@ -117,25 +110,20 @@
     m_mediaElement = videoElement.ptr();
     videoElement->setAttributeWithoutSynchronization(controlsAttr, emptyAtom);
     videoElement->setAttributeWithoutSynchronization(autoplayAttr, emptyAtom);
-    videoElement->setAttributeWithoutSynchronization(nameAttr, AtomicString("media", AtomicString::ConstructFromLiteral));
+    videoElement->setAttributeWithoutSynchronization(playsinlineAttr, emptyAtom);
+    videoElement->setSrc(document.url());
+    if (auto* loader = document.loader())
+        videoElement->setAttributeWithoutSynchronization(typeAttr, loader->responseMIMEType());
 
-    StringBuilder elementStyle;
-    elementStyle.appendLiteral("max-width: 100%; max-height: 100%;");
+    if (!RuntimeEnabledFeatures::sharedFeatures().modernMediaControlsEnabled()) {
+        StringBuilder elementStyle;
+        elementStyle.appendLiteral("max-width: 100%; max-height: 100%;");
 #if PLATFORM(IOS)
-    elementStyle.appendLiteral("width: 100%; height: auto;");
+        elementStyle.appendLiteral("width: 100%; height: auto;");
 #endif
-    if (RuntimeEnabledFeatures::sharedFeatures().modernMediaControlsEnabled()) {
-        elementStyle.appendLiteral("min-height: 50px;");
+        videoElement->setAttribute(styleAttr, elementStyle.toString());
     }
-    videoElement->setAttribute(styleAttr, elementStyle.toString());
 
-    auto sourceElement = HTMLSourceElement::create(document);
-    sourceElement->setSrc(document.url());
-
-    if (auto* loader = document.loader())
-        sourceElement->setType(loader->responseMIMEType());
-
-    videoElement->appendChild(sourceElement);
     body->appendChild(videoElement);
 
     Frame* frame = document.frame();
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to