<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[208537] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/208537">208537</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2016-11-10 07:43:53 -0800 (Thu, 10 Nov 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>[Modern Media Controls] Media Controller: update controls based on fullscreen playback on macOS
https://bugs.webkit.org/show_bug.cgi?id=164554
&lt;rdar://problem/29183439&gt;

Patch by Antoine Quint &lt;graouts@apple.com&gt; on 2016-11-10
Reviewed by Dean Jackson.

Source/WebCore:

When toggling fullscreen on macOS, toggle between MacOSInlineMediaControls and MacOSFullscreenMediaControls.
To facilitate this, support objects are created and destroyed when changing the controls in order for the
right control objects to be hooked up to the media controller. A new destroy() method on MediaControllerSupport
subclasses can be overridden to remove event listeners added by support objects in their constructor.

Test: media/modern-media-controls/media-controller/media-controller-fullscreen-change.html

* Modules/modern-media-controls/media/fullscreen-support.js:
(FullscreenSupport.prototype.destroy):
* Modules/modern-media-controls/media/media-controller-support.js:
(MediaControllerSupport.prototype.destroy):
* Modules/modern-media-controls/media/media-controller.js:
(MediaController):
(MediaController.prototype.get layoutTraits):
(MediaController.prototype.handleEvent):
(MediaController.prototype._updateControlsIfNeeded):
(MediaController.prototype._controlsClass):

LayoutTests:

Adding a new test to check that we use fullscreen controls on macOS once we've entered fullscreen.

* media/modern-media-controls/media-controller/media-controller-fullscreen-change-expected.txt: Added.
* media/modern-media-controls/media-controller/media-controller-fullscreen-change.html: Added.
* platform/ios-simulator/TestExpectations:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsplatformiossimulatorTestExpectations">trunk/LayoutTests/platform/ios-simulator/TestExpectations</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreModulesmodernmediacontrolsmediafullscreensupportjs">trunk/Source/WebCore/Modules/modern-media-controls/media/fullscreen-support.js</a></li>
<li><a href="#trunkSourceWebCoreModulesmodernmediacontrolsmediamediacontrollersupportjs">trunk/Source/WebCore/Modules/modern-media-controls/media/media-controller-support.js</a></li>
<li><a href="#trunkSourceWebCoreModulesmodernmediacontrolsmediamediacontrollerjs">trunk/Source/WebCore/Modules/modern-media-controls/media/media-controller.js</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsmediamodernmediacontrolsmediacontrollermediacontrollerfullscreenchangeexpectedtxt">trunk/LayoutTests/media/modern-media-controls/media-controller/media-controller-fullscreen-change-expected.txt</a></li>
<li><a href="#trunkLayoutTestsmediamodernmediacontrolsmediacontrollermediacontrollerfullscreenchangehtml">trunk/LayoutTests/media/modern-media-controls/media-controller/media-controller-fullscreen-change.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (208536 => 208537)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2016-11-10 15:02:08 UTC (rev 208536)
+++ trunk/LayoutTests/ChangeLog        2016-11-10 15:43:53 UTC (rev 208537)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2016-11-10  Antoine Quint  &lt;graouts@apple.com&gt;
+
+        [Modern Media Controls] Media Controller: update controls based on fullscreen playback on macOS
+        https://bugs.webkit.org/show_bug.cgi?id=164554
+        &lt;rdar://problem/29183439&gt;
+
+        Reviewed by Dean Jackson.
+
+        Adding a new test to check that we use fullscreen controls on macOS once we've entered fullscreen.
+
+        * media/modern-media-controls/media-controller/media-controller-fullscreen-change-expected.txt: Added.
+        * media/modern-media-controls/media-controller/media-controller-fullscreen-change.html: Added.
+        * platform/ios-simulator/TestExpectations:
+
</ins><span class="cx"> 2016-11-08  Sergio Villar Senin  &lt;svillar@igalia.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [css-grid] Fix fr tracks sizing under min|max-size constraints
</span></span></pre></div>
<a id="trunkLayoutTestsmediamodernmediacontrolsmediacontrollermediacontrollerfullscreenchangeexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/modern-media-controls/media-controller/media-controller-fullscreen-change-expected.txt (0 => 208537)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/modern-media-controls/media-controller/media-controller-fullscreen-change-expected.txt                                (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/media-controller/media-controller-fullscreen-change-expected.txt        2016-11-10 15:43:53 UTC (rev 208537)
</span><span class="lines">@@ -0,0 +1,17 @@
</span><ins>+Testing the MediaController behavior when entering and leaving fullscreen.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+Media entered fullscreen
+PASS mediaController.layoutTraits is LayoutTraits.macOS | LayoutTraits.Fullscreen
+PASS mediaController.controls instanceof MacOSFullscreenMediaControls is true
+
+Media exited fullscreen
+PASS mediaController.layoutTraits is LayoutTraits.macOS
+PASS mediaController.controls instanceof MacOSInlineMediaControls is true
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsmediamodernmediacontrolsmediacontrollermediacontrollerfullscreenchangehtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/modern-media-controls/media-controller/media-controller-fullscreen-change.html (0 => 208537)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/modern-media-controls/media-controller/media-controller-fullscreen-change.html                                (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/media-controller/media-controller-fullscreen-change.html        2016-11-10 15:43:53 UTC (rev 208537)
</span><span class="lines">@@ -0,0 +1,64 @@
</span><ins>+&lt;script src=&quot;../../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../resources/media-controls-loader.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
+&lt;body&gt;
+&lt;video src=&quot;../../content/test.mp4&quot; style=&quot;width: 320px; height: 240px;&quot;&gt;&lt;/video&gt;
+&lt;div id=&quot;shadow&quot;&gt;&lt;/div&gt;
+&lt;script type=&quot;text/javascript&quot;&gt;
+
+window.jsTestIsAsync = true;
+
+description(&quot;Testing the &lt;code&gt;MediaController&lt;/code&gt; behavior when entering and leaving fullscreen.&quot;);
+
+const shadowRoot = document.querySelector(&quot;div#shadow&quot;).attachShadow({ mode: &quot;open&quot; });
+const media = document.querySelector(&quot;video&quot;);
+const mediaController = createControls(shadowRoot, media, null);
+
+const button = document.body.appendChild(document.createElement(&quot;button&quot;));
+
+function enterFullscreen()
+{
+    if (!(&quot;eventSender&quot; in window)) {
+        debug(&quot;This test is designed to run in DRT&quot;);
+        return;
+    }
+
+    // Click a button so we may enter fullscreen.
+    button.addEventListener(&quot;click&quot;, event =&gt; {
+        try {
+            media.webkitEnterFullscreen();
+        } catch(e) {
+            debug(&quot;Toggling fullscreen failed&quot;);
+            finishJSTest();
+        }
+    });
+
+    eventSender.mouseMoveTo(button.offsetLeft + 1, button.offsetTop + 1);
+    eventSender.mouseDown();
+    eventSender.mouseUp();
+}
+
+media.addEventListener(&quot;webkitfullscreenchange&quot;, function() {
+    if (media.webkitDisplayingFullscreen) {
+        debug(&quot;Media entered fullscreen&quot;);
+        shouldBe(&quot;mediaController.layoutTraits&quot;, &quot;LayoutTraits.macOS | LayoutTraits.Fullscreen&quot;);
+        shouldBeTrue(&quot;mediaController.controls instanceof MacOSFullscreenMediaControls&quot;);
+        debug(&quot;&quot;);
+        media.webkitExitFullscreen()
+    } else {
+        debug(&quot;Media exited fullscreen&quot;);
+        shouldBe(&quot;mediaController.layoutTraits&quot;, &quot;LayoutTraits.macOS&quot;);
+        shouldBeTrue(&quot;mediaController.controls instanceof MacOSInlineMediaControls&quot;);
+
+        debug(&quot;&quot;);
+        shadowRoot.host.remove();
+        media.remove();
+        button.remove();
+        finishJSTest();
+    }
+});
+
+media.addEventListener(&quot;loadedmetadata&quot;, enterFullscreen);
+
+&lt;/script&gt;
+&lt;script src=&quot;../../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsplatformiossimulatorTestExpectations"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/platform/ios-simulator/TestExpectations (208536 => 208537)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/ios-simulator/TestExpectations        2016-11-10 15:02:08 UTC (rev 208536)
+++ trunk/LayoutTests/platform/ios-simulator/TestExpectations        2016-11-10 15:43:53 UTC (rev 208537)
</span><span class="lines">@@ -2748,3 +2748,6 @@
</span><span class="cx"> media/modern-media-controls/airplay-support/airplay-support.html [ Skip ]
</span><span class="cx"> media/modern-media-controls/pip-support [ Skip ]
</span><span class="cx"> media/modern-media-controls/placard-support [ Skip ]
</span><ins>+
+# This test is Mac-specific since it checks that we have custom controls in fullscreen.
+media/modern-media-controls/media-controller/media-controller-fullscreen-change.html [ Skip ]
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (208536 => 208537)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-11-10 15:02:08 UTC (rev 208536)
+++ trunk/Source/WebCore/ChangeLog        2016-11-10 15:43:53 UTC (rev 208537)
</span><span class="lines">@@ -1,3 +1,29 @@
</span><ins>+2016-11-10  Antoine Quint  &lt;graouts@apple.com&gt;
+
+        [Modern Media Controls] Media Controller: update controls based on fullscreen playback on macOS
+        https://bugs.webkit.org/show_bug.cgi?id=164554
+        &lt;rdar://problem/29183439&gt;
+
+        Reviewed by Dean Jackson.
+
+        When toggling fullscreen on macOS, toggle between MacOSInlineMediaControls and MacOSFullscreenMediaControls.
+        To facilitate this, support objects are created and destroyed when changing the controls in order for the
+        right control objects to be hooked up to the media controller. A new destroy() method on MediaControllerSupport
+        subclasses can be overridden to remove event listeners added by support objects in their constructor.
+
+        Test: media/modern-media-controls/media-controller/media-controller-fullscreen-change.html
+
+        * Modules/modern-media-controls/media/fullscreen-support.js:
+        (FullscreenSupport.prototype.destroy):
+        * Modules/modern-media-controls/media/media-controller-support.js:
+        (MediaControllerSupport.prototype.destroy):
+        * Modules/modern-media-controls/media/media-controller.js:
+        (MediaController):
+        (MediaController.prototype.get layoutTraits):
+        (MediaController.prototype.handleEvent):
+        (MediaController.prototype._updateControlsIfNeeded):
+        (MediaController.prototype._controlsClass):
+
</ins><span class="cx"> 2016-11-10  Carlos Garcia Campos  &lt;cgarcia@igalia.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [Linux] Memory values shown by memory pressure handler logger are not useful
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmodernmediacontrolsmediafullscreensupportjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/modern-media-controls/media/fullscreen-support.js (208536 => 208537)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/modern-media-controls/media/fullscreen-support.js        2016-11-10 15:02:08 UTC (rev 208536)
+++ trunk/Source/WebCore/Modules/modern-media-controls/media/fullscreen-support.js        2016-11-10 15:43:53 UTC (rev 208537)
</span><span class="lines">@@ -35,6 +35,17 @@
</span><span class="cx">             videoTracks.addEventListener(eventType, this);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    // Public
+
+    destroy()
+    {
+        super.destroy();
+
+        const videoTracks = this.mediaController.media.videoTracks;
+        for (let eventType of [&quot;change&quot;, &quot;addtrack&quot;, &quot;removetrack&quot;])
+            videoTracks.removeEventListener(eventType, this);
+    }
+
</ins><span class="cx">     // Protected
</span><span class="cx"> 
</span><span class="cx">     get control()
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmodernmediacontrolsmediamediacontrollersupportjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/modern-media-controls/media/media-controller-support.js (208536 => 208537)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/modern-media-controls/media/media-controller-support.js        2016-11-10 15:02:08 UTC (rev 208536)
+++ trunk/Source/WebCore/Modules/modern-media-controls/media/media-controller-support.js        2016-11-10 15:43:53 UTC (rev 208537)
</span><span class="lines">@@ -41,6 +41,18 @@
</span><span class="cx">         this.syncControl();
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    // Public
+
+    destroy()
+    {
+        const media = this.mediaController.media;
+        for (let eventType of this.mediaEvents)
+            media.removeEventListener(eventType, this);
+
+        if (this.control)
+            this.control.uiDelegate = null;
+    }
+
</ins><span class="cx">     // Protected
</span><span class="cx"> 
</span><span class="cx">     get control()
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmodernmediacontrolsmediamediacontrollerjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/modern-media-controls/media/media-controller.js (208536 => 208537)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/modern-media-controls/media/media-controller.js        2016-11-10 15:02:08 UTC (rev 208536)
+++ trunk/Source/WebCore/Modules/modern-media-controls/media/media-controller.js        2016-11-10 15:43:53 UTC (rev 208537)
</span><span class="lines">@@ -32,28 +32,19 @@
</span><span class="cx">         this.media = media;
</span><span class="cx">         this.host = host;
</span><span class="cx"> 
</span><del>-        // FIXME: This should get set dynamically based on the current environment.
-        this.layoutTraits = LayoutTraits.macOS;
</del><ins>+        this._updateControlsIfNeeded();
</ins><span class="cx"> 
</span><del>-        this.controls = new MacOSInlineMediaControls
-        shadowRoot.appendChild(this.controls.element);        
</del><ins>+        media.addEventListener(&quot;resize&quot;, this);
</ins><span class="cx"> 
</span><del>-        new AirplaySupport(this);
-        new ElapsedTimeSupport(this);
-        new FullscreenSupport(this);
-        new MuteSupport(this);
-        new PiPSupport(this);
-        new PlacardSupport(this);
-        new PlaybackSupport(this);
-        new RemainingTimeSupport(this);
-        new ScrubbingSupport(this);
-        new SkipBackSupport(this);
-        new StartSupport(this);
-        new StatusSupport(this);
-        new VolumeSupport(this);
</del><ins>+        media.addEventListener(&quot;webkitfullscreenchange&quot;, this);
+    }
</ins><span class="cx"> 
</span><del>-        this._updateControlsSize();
-        media.addEventListener(&quot;resize&quot;, this);
</del><ins>+    get layoutTraits()
+    {
+        let traits = window.navigator.platform === &quot;MacIntel&quot; ? LayoutTraits.macOS : LayoutTraits.iOS;
+        if (this.media.webkitDisplayingFullscreen)
+            traits = traits | LayoutTraits.Fullscreen;
+        return traits;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Protected
</span><span class="lines">@@ -72,10 +63,40 @@
</span><span class="cx">     {
</span><span class="cx">         if (event.type === &quot;resize&quot; &amp;&amp; event.currentTarget === this.media)
</span><span class="cx">             this._updateControlsSize();
</span><ins>+        else if (event.type === &quot;webkitfullscreenchange&quot; &amp;&amp; event.currentTarget === this.media)
+            this._updateControlsIfNeeded();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Private
</span><span class="cx"> 
</span><ins>+    _updateControlsIfNeeded()
+    {
+        const previousControls = this.controls;
+        const ControlsClass = this._controlsClass();
+        if (previousControls &amp;&amp; previousControls.constructor === ControlsClass)
+            return;
+
+        // Before we reset the .controls property, we need to destroy the previous
+        // supporting objects so we don't leak.
+        if (this._supportingObjects) {
+            for (let supportingObject of this._supportingObjects)
+                supportingObject.destroy();
+        }
+
+        this.controls = new ControlsClass;
+
+        if (previousControls)
+            this.shadowRoot.replaceChild(this.controls.element, previousControls.element);
+        else
+            this.shadowRoot.appendChild(this.controls.element);        
+
+        this._updateControlsSize();
+
+        this._supportingObjects = [AirplaySupport, ElapsedTimeSupport, FullscreenSupport, MuteSupport, PiPSupport, PlacardSupport, PlaybackSupport, RemainingTimeSupport, ScrubbingSupport, SkipBackSupport, StartSupport, StatusSupport, VolumeSupport].map(SupportClass =&gt; {
+            return new SupportClass(this);
+        }, this);
+    }
+
</ins><span class="cx">     _updateControlsSize()
</span><span class="cx">     {
</span><span class="cx">         this.controls.width = this.media.offsetWidth;
</span><span class="lines">@@ -82,4 +103,12 @@
</span><span class="cx">         this.controls.height = this.media.offsetHeight;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    _controlsClass()
+    {
+        const layoutTraits = this.layoutTraits;
+        if (layoutTraits &amp; LayoutTraits.Fullscreen)
+            return MacOSFullscreenMediaControls;
+        return MacOSInlineMediaControls;
+    }
+
</ins><span class="cx"> }
</span></span></pre>
</div>
</div>

</body>
</html>