<!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>[180347] trunk/Source/WebCore</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/180347">180347</a></dd>
<dt>Author</dt> <dd>dino@apple.com</dd>
<dt>Date</dt> <dd>2015-02-19 10:36:40 -0800 (Thu, 19 Feb 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Sufficiently small media controls should remove toolbar elements
https://bugs.webkit.org/show_bug.cgi?id=141780
&lt;rdar://problem/16548548&gt;
&lt;rdar://problem/17598778&gt;
&lt;rdar://problem/18351963&gt;

Reviewed by Eric Carlson.

Implement some logic where elements on the media controls are
hidden when there isn't enough room. We start by dropping
the scrubber, then the various buttons on the right hand
side.

This solution isn't perfect. If we had perfection, it would
be because we get resize events and respond accordingly. Instead
we check the size when the user has pinch-zoomed, or when
we start/stop playing.

This is going to cause some extra layout, because we need
to know the size of things before we can work out which
bits to hide.

* Modules/mediacontrols/mediaControlsiOS.css:
(::-webkit-media-controls): Remove the minimum width. This can
cause the controls to get clipped.
(audio::-webkit-media-controls-spacer): Add this empty element to
replace the scrubber when it is hidden.
(audio::-webkit-media-controls-timeline-container):
* Modules/mediacontrols/mediaControlsiOS.js:
(ControllerIOS): Remember our size so we don't churn.
(ControllerIOS.prototype.createControls): Create a new spacer element.
(ControllerIOS.prototype.configureInlineControls):
(ControllerIOS.prototype.showControls): Check if we need to hide stuff.
(ControllerIOS.prototype.updateControls):
(ControllerIOS.prototype.setPlaying): Ditto.
(ControllerIOS.prototype.set pageScaleFactor): Ditto.
(ControllerIOS.prototype.scheduleUpdateLayoutForDisplayedWidth): Trigger an update
asap. In this case it's probably ok to be in a bad state for a frame, or
we are inside setup and we know that we'll layout soon.
(ControllerIOS.prototype.updateLayoutForDisplayedWidth): The actual code
that hides elements.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreModulesmediacontrolsmediaControlsiOScss">trunk/Source/WebCore/Modules/mediacontrols/mediaControlsiOS.css</a></li>
<li><a href="#trunkSourceWebCoreModulesmediacontrolsmediaControlsiOSjs">trunk/Source/WebCore/Modules/mediacontrols/mediaControlsiOS.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (180346 => 180347)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2015-02-19 16:47:30 UTC (rev 180346)
+++ trunk/Source/WebCore/ChangeLog        2015-02-19 18:36:40 UTC (rev 180347)
</span><span class="lines">@@ -1,3 +1,47 @@
</span><ins>+2015-02-18  Dean Jackson  &lt;dino@apple.com&gt;
+
+        Sufficiently small media controls should remove toolbar elements
+        https://bugs.webkit.org/show_bug.cgi?id=141780
+        &lt;rdar://problem/16548548&gt;
+        &lt;rdar://problem/17598778&gt;
+        &lt;rdar://problem/18351963&gt;
+
+        Reviewed by Eric Carlson.
+
+        Implement some logic where elements on the media controls are
+        hidden when there isn't enough room. We start by dropping
+        the scrubber, then the various buttons on the right hand
+        side.
+
+        This solution isn't perfect. If we had perfection, it would
+        be because we get resize events and respond accordingly. Instead
+        we check the size when the user has pinch-zoomed, or when
+        we start/stop playing.
+
+        This is going to cause some extra layout, because we need
+        to know the size of things before we can work out which
+        bits to hide.
+
+        * Modules/mediacontrols/mediaControlsiOS.css:
+        (::-webkit-media-controls): Remove the minimum width. This can
+        cause the controls to get clipped.
+        (audio::-webkit-media-controls-spacer): Add this empty element to
+        replace the scrubber when it is hidden.
+        (audio::-webkit-media-controls-timeline-container):
+        * Modules/mediacontrols/mediaControlsiOS.js:
+        (ControllerIOS): Remember our size so we don't churn.
+        (ControllerIOS.prototype.createControls): Create a new spacer element.
+        (ControllerIOS.prototype.configureInlineControls):
+        (ControllerIOS.prototype.showControls): Check if we need to hide stuff.
+        (ControllerIOS.prototype.updateControls):
+        (ControllerIOS.prototype.setPlaying): Ditto.
+        (ControllerIOS.prototype.set pageScaleFactor): Ditto.
+        (ControllerIOS.prototype.scheduleUpdateLayoutForDisplayedWidth): Trigger an update
+        asap. In this case it's probably ok to be in a bad state for a frame, or
+        we are inside setup and we know that we'll layout soon.
+        (ControllerIOS.prototype.updateLayoutForDisplayedWidth): The actual code
+        that hides elements.
+
</ins><span class="cx"> 2015-02-19  Tim Horton  &lt;timothy_horton@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Move the software-only ImageBuffer::m_context to ImageBufferData
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmediacontrolsmediaControlsiOScss"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/mediacontrols/mediaControlsiOS.css (180346 => 180347)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/mediacontrols/mediaControlsiOS.css        2015-02-19 16:47:30 UTC (rev 180346)
+++ trunk/Source/WebCore/Modules/mediacontrols/mediaControlsiOS.css        2015-02-19 18:36:40 UTC (rev 180347)
</span><span class="lines">@@ -59,7 +59,6 @@
</span><span class="cx">     -webkit-flex-direction: column;
</span><span class="cx">     font-family: -apple-system-font;
</span><span class="cx">     overflow: hidden;
</span><del>-    min-width: 260px;
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> video::-webkit-media-controls-panel input[type=&quot;button&quot;],
</span><span class="lines">@@ -301,6 +300,18 @@
</span><span class="cx">     -webkit-order: 5;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/* ================== SPACER ====================== */
+
+video::-webkit-media-controls-spacer,
+audio::-webkit-media-controls-spacer {
+    -webkit-appearance: none !important;
+    -webkit-flex: 1 1 0; /* Should be the same as the timeline container. */
+    -webkit-order: 2;
+    height: 8px;
+    margin: 0;
+    background-color: transparent !important;
+}
+
</ins><span class="cx"> /* ================== TIMELINE ====================== */
</span><span class="cx"> 
</span><span class="cx"> video::-webkit-media-controls-timeline,
</span><span class="lines">@@ -395,7 +406,7 @@
</span><span class="cx">     -webkit-flex-direction: row;
</span><span class="cx">     -webkit-align-items: center;
</span><span class="cx">     -webkit-user-select: none;
</span><del>-    -webkit-flex: 1 1 0;
</del><ins>+    -webkit-flex: 1 1 0; /* Any changes here should also be made on the spacer. */
</ins><span class="cx">     position: relative;
</span><span class="cx">     padding: 0;
</span><span class="cx">     -webkit-order: 2;
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmediacontrolsmediaControlsiOSjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/mediacontrols/mediaControlsiOS.js (180346 => 180347)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/mediacontrols/mediaControlsiOS.js        2015-02-19 16:47:30 UTC (rev 180346)
+++ trunk/Source/WebCore/Modules/mediacontrols/mediaControlsiOS.js        2015-02-19 18:36:40 UTC (rev 180347)
</span><span class="lines">@@ -18,10 +18,18 @@
</span><span class="cx">     this.updateWirelessPlaybackStatus();
</span><span class="cx">     this.setNeedsTimelineMetricsUpdate();
</span><span class="cx"> 
</span><ins>+    this._timelineIsHidden = false;
+    this._currentDisplayWidth = 0;
+    this.scheduleUpdateLayoutForDisplayedWidth();
+
</ins><span class="cx">     host.controlsDependOnPageScaleFactor = true;
</span><span class="cx">     this.doingSetup = false;
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+/* Constants */
+ControllerIOS.MinimumTimelineWidth = 200;
+ControllerIOS.ButtonWidth = 42;
+
</ins><span class="cx"> /* Enums */
</span><span class="cx"> ControllerIOS.StartPlaybackControls = 2;
</span><span class="cx"> 
</span><span class="lines">@@ -151,6 +159,10 @@
</span><span class="cx">         var panelCompositedParent = this.controls.panelCompositedParent = document.createElement('div');
</span><span class="cx">         panelCompositedParent.setAttribute('pseudo', '-webkit-media-controls-panel-composited-parent');
</span><span class="cx"> 
</span><ins>+        var spacer = this.controls.spacer = document.createElement('div');
+        spacer.setAttribute('pseudo', '-webkit-media-controls-spacer');
+        spacer.classList.add(this.ClassNames.hidden);
+
</ins><span class="cx">         var inlinePlaybackPlaceholder = this.controls.inlinePlaybackPlaceholder = document.createElement('div');
</span><span class="cx">         inlinePlaybackPlaceholder.setAttribute('pseudo', '-webkit-media-controls-inline-playback-placeholder');
</span><span class="cx">         if (!ControllerIOS.gSimulateOptimizedFullscreenAvailable)
</span><span class="lines">@@ -221,6 +233,7 @@
</span><span class="cx">     configureInlineControls: function() {
</span><span class="cx">         this.controls.panel.appendChild(this.controls.playButton);
</span><span class="cx">         this.controls.panel.appendChild(this.controls.statusDisplay);
</span><ins>+        this.controls.panel.appendChild(this.controls.spacer);
</ins><span class="cx">         this.controls.panel.appendChild(this.controls.timelineBox);
</span><span class="cx">         this.controls.panel.appendChild(this.controls.wirelessTargetPicker);
</span><span class="cx">         if (!this.isLive) {
</span><span class="lines">@@ -248,6 +261,7 @@
</span><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     showControls: function() {
</span><ins>+        this.updateLayoutForDisplayedWidth();
</ins><span class="cx">         this.updateTime(true);
</span><span class="cx">         this.updateProgress(true);
</span><span class="cx">         Controller.prototype.showControls.call(this);
</span><span class="lines">@@ -269,6 +283,7 @@
</span><span class="cx">         else
</span><span class="cx">             this.setControlsType(Controller.InlineControls);
</span><span class="cx"> 
</span><ins>+        this.updateLayoutForDisplayedWidth();
</ins><span class="cx">         this.setNeedsTimelineMetricsUpdate();
</span><span class="cx">     },
</span><span class="cx"> 
</span><span class="lines">@@ -605,8 +620,10 @@
</span><span class="cx"> 
</span><span class="cx">         this.updateControls();
</span><span class="cx"> 
</span><del>-        if (isPlaying &amp;&amp; this.isAudio())
</del><ins>+        if (isPlaying &amp;&amp; this.isAudio() &amp;&amp; !this._timelineIsHidden) {
</ins><span class="cx">             this.controls.timelineBox.classList.remove(this.ClassNames.hidden);
</span><ins>+            this.controls.spacer.classList.add(this.ClassNames.hidden);
+        }
</ins><span class="cx"> 
</span><span class="cx">         if (isPlaying)
</span><span class="cx">             this.hasPlayed = true;
</span><span class="lines">@@ -654,6 +671,7 @@
</span><span class="cx">                 this.controls.panel.style.webkitTransform = scaleTransform;
</span><span class="cx">                 this.setNeedsTimelineMetricsUpdate();
</span><span class="cx">                 this.updateProgress();
</span><ins>+                this.scheduleUpdateLayoutForDisplayedWidth();
</ins><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">     },
</span><span class="lines">@@ -686,6 +704,69 @@
</span><span class="cx">         this.handlePresentationModeChange(event);
</span><span class="cx">     },
</span><span class="cx"> 
</span><ins>+    scheduleUpdateLayoutForDisplayedWidth: function ()
+    {
+        setTimeout(function () {
+            this.updateLayoutForDisplayedWidth();
+        }.bind(this), 0);
+    },
+
+    updateLayoutForDisplayedWidth: function()
+    {
+        if (!this.controls || !this.controls.panel)
+            return;
+
+        var visibleWidth = this.controls.panel.getBoundingClientRect().width * this._pageScaleFactor;
+        if (visibleWidth &lt;= 0 || visibleWidth == this._currentDisplayWidth)
+            return;
+
+        this._currentDisplayWidth = visibleWidth;
+
+        // We need to work out how many right-hand side buttons are available.
+        this.updateWirelessTargetAvailable();
+        this.updateFullscreenButtons();
+
+        var visibleButtonWidth = ControllerIOS.ButtonWidth; // We always try to show the fullscreen button.
+
+        if (!this.controls.wirelessTargetPicker.classList.contains(this.ClassNames.hidden))
+            visibleButtonWidth += ControllerIOS.ButtonWidth;
+        if (!this.controls.optimizedFullscreenButton.classList.contains(this.ClassNames.hidden))
+            visibleButtonWidth += ControllerIOS.ButtonWidth;
+
+        // Check if there is enough room for the scrubber.
+        if ((visibleWidth - visibleButtonWidth) &lt; ControllerIOS.MinimumTimelineWidth) {
+            this.controls.timelineBox.classList.add(this.ClassNames.hidden);
+            this.controls.spacer.classList.remove(this.ClassNames.hidden);
+            this._timelineIsHidden = true;
+        } else {
+            if (!this.isAudio() || this.hasPlayed) {
+                this.controls.timelineBox.classList.remove(this.ClassNames.hidden);
+                this.controls.spacer.classList.add(this.ClassNames.hidden);
+                this._timelineIsHidden = false;
+            } else
+                this.controls.spacer.classList.remove(this.ClassNames.hidden);
+        }
+
+        // Drop the airplay button if there isn't enough space.
+        if (visibleWidth &lt; visibleButtonWidth) {
+            this.controls.wirelessTargetPicker.classList.add(this.ClassNames.hidden);
+            visibleButtonWidth -= ControllerIOS.ButtonWidth;
+        }
+
+        // Drop the optimized fullscreen button if there still isn't enough space.
+        if (visibleWidth &lt; visibleButtonWidth) {
+            this.controls.optimizedFullscreenButton.classList.add(this.ClassNames.hidden);
+            visibleButtonWidth -= ControllerIOS.ButtonWidth;
+        }
+
+        // And finally, drop the fullscreen button as a last resort.
+        if (visibleWidth &lt; visibleButtonWidth) {
+            this.controls.fullscreenButton.classList.add(this.ClassNames.hidden);
+            visibleButtonWidth -= ControllerIOS.ButtonWidth;
+        } else
+            this.controls.fullscreenButton.classList.remove(this.ClassNames.hidden);
+    },
+
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> Object.create(Controller.prototype).extend(ControllerIOS.prototype);
</span></span></pre>
</div>
</div>

</body>
</html>