<!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>[184416] 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/184416">184416</a></dd>
<dt>Author</dt> <dd>jer.noble@apple.com</dd>
<dt>Date</dt> <dd>2015-05-15 14:30:18 -0700 (Fri, 15 May 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>[MediaControls] Refactor media controls &amp; bring improvements made to iOS controls to Mac.
https://bugs.webkit.org/show_bug.cgi?id=144973

Reviewed by Dean Jackson.

Pull improvements made to the iOS media controls back into the Mac controls by moving
code from mediaControlsiOS.js into MediaControlsApple.js.

The largest refactored feature is the ability to drop individual controls from the media
controls when the video is too small to contain them. To allow these controls to resize
dynamically, a new &quot;resize&quot; event is fired inside the media element's shadow DOM.

* Modules/mediacontrols/mediaControlsApple.css:
(audio::-webkit-media-controls-panel .dropped): Added; sets &quot;display: none&quot;.
* Modules/mediacontrols/mediaControlsApple.js:
(Controller): Set defaults for new variables.
(Controller.prototype.updateControls): Update the controls width; moved from iOS.js.
(Controller.prototype.handleReadyStateChange): Update the controls; moved from iOS.js.
(Controller.prototype.handleTimeUpdate): Update the progress; moved from iOS.js.
(Controller.prototype.handleTimelineInput): Pause if scrubbing; moved from iOS.js.
(Controller.prototype.handleTimelineChange): Update the progress; moved from iOS.js.
(Controller.prototype.showControls): Update the controls width; moved from iOS.js.
(Controller.prototype.hideControls): Removed _potentiallyScrubbing check; not needed due to changes
    to controlsAlwaysVisible().
(Controller.prototype.scheduleUpdateLayoutForDisplayedWidth): Moved from iOS.js.
(Controller.prototype.isControlVisible): Added; checks whether control is parented &amp; not hidden.
(Controller.prototype.updateLayoutForDisplayedWidth): Moved from iOS.js and refactored.
(Controller.prototype.controlsAlwaysVisible): Return true if scrubbing.
(Controller.prototype.updateHasAudio): Check currentPlaybackTargetIsWireless(); moved from iOS.js.
(Controller.prototype.get scrubbing): Simple getter for _scrubbing.
(Controller.prototype.set scrubbing): Check play state if scrubbing; start playback (if necessary)
    if not scrubbing.
(Controller.prototype.get pageScaleFactor): Moved from iOS.js.
(Controller.prototype.set pageScaleFactor): Ditto.
(Controller.prototype.handleRootResize): Schedule an update of the contrtols width.

Remove a bunch of newly unnecessary code from the iOS media controls:

* Modules/mediacontrols/mediaControlsiOS.js:
(ControllerIOS):
(ControllerIOS.prototype.createControls): Remove ivars moved into Apple.js.
(ControllerIOS.prototype.configureInlineControls): Remove spacer; made unnecessary.
(ControllerIOS.prototype.showControls): Deleted.
(ControllerIOS.prototype.updateTime): Deleted.
(ControllerIOS.prototype.handleTimelineTouchStart): Just call &quot;scrubbing = true&quot;, handled in Apple.js.
(ControllerIOS.prototype.handleTimelineTouchEnd): Just call &quot;scrubbing = false&quot;, handled in Apple.js.
(ControllerIOS.prototype.handleReadyStateChange): Deleted.
(ControllerIOS.prototype.setPlaying): Don't check _timelineIsHidden; not needed.
(ControllerIOS.prototype.get pageScaleFactor): Deleted.
(ControllerIOS.prototype.set pageScaleFactor): Deleted.
(ControllerIOS.prototype.scheduleUpdateLayoutForDisplayedWidth): Deleted.
(ControllerIOS.prototypeupdateLayoutForDisplayedWidth): Deleted.

Fire a &quot;resize&quot; event at the shadow DOM root when layout results in a size change.

* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::layoutSizeChanged): Fire the &quot;resize&quot; event at the shadow DOM.
* html/HTMLMediaElement.h:
* rendering/RenderMedia.cpp:
(WebCore::RenderMedia::layout): Trigger layoutSizeChanged()
* rendering/RenderMedia.h:

Drive-by fixes:

* Modules/mediacontrols/mediaControlsApple.js:
(Controller.prototype.createControls): aria-label text is totally wrong; removed.
(Controller.prototype.updateWirelessPlaybackStatus): Use class-names to hide controls, not inline styles.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreModulesmediacontrolsmediaControlsApplecss">trunk/Source/WebCore/Modules/mediacontrols/mediaControlsApple.css</a></li>
<li><a href="#trunkSourceWebCoreModulesmediacontrolsmediaControlsApplejs">trunk/Source/WebCore/Modules/mediacontrols/mediaControlsApple.js</a></li>
<li><a href="#trunkSourceWebCoreModulesmediacontrolsmediaControlsiOSjs">trunk/Source/WebCore/Modules/mediacontrols/mediaControlsiOS.js</a></li>
<li><a href="#trunkSourceWebCorehtmlHTMLMediaElementcpp">trunk/Source/WebCore/html/HTMLMediaElement.cpp</a></li>
<li><a href="#trunkSourceWebCorehtmlHTMLMediaElementh">trunk/Source/WebCore/html/HTMLMediaElement.h</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderMediacpp">trunk/Source/WebCore/rendering/RenderMedia.cpp</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderMediah">trunk/Source/WebCore/rendering/RenderMedia.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (184415 => 184416)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2015-05-15 21:11:39 UTC (rev 184415)
+++ trunk/Source/WebCore/ChangeLog        2015-05-15 21:30:18 UTC (rev 184416)
</span><span class="lines">@@ -1,3 +1,73 @@
</span><ins>+2015-05-15  Jer Noble  &lt;jer.noble@apple.com&gt;
+
+        [MediaControls] Refactor media controls &amp; bring improvements made to iOS controls to Mac.
+        https://bugs.webkit.org/show_bug.cgi?id=144973
+
+        Reviewed by Dean Jackson.
+
+        Pull improvements made to the iOS media controls back into the Mac controls by moving
+        code from mediaControlsiOS.js into MediaControlsApple.js.
+
+        The largest refactored feature is the ability to drop individual controls from the media
+        controls when the video is too small to contain them. To allow these controls to resize
+        dynamically, a new &quot;resize&quot; event is fired inside the media element's shadow DOM.
+
+        * Modules/mediacontrols/mediaControlsApple.css:
+        (audio::-webkit-media-controls-panel .dropped): Added; sets &quot;display: none&quot;.
+        * Modules/mediacontrols/mediaControlsApple.js:
+        (Controller): Set defaults for new variables.
+        (Controller.prototype.updateControls): Update the controls width; moved from iOS.js.
+        (Controller.prototype.handleReadyStateChange): Update the controls; moved from iOS.js.
+        (Controller.prototype.handleTimeUpdate): Update the progress; moved from iOS.js.
+        (Controller.prototype.handleTimelineInput): Pause if scrubbing; moved from iOS.js.
+        (Controller.prototype.handleTimelineChange): Update the progress; moved from iOS.js.
+        (Controller.prototype.showControls): Update the controls width; moved from iOS.js.
+        (Controller.prototype.hideControls): Removed _potentiallyScrubbing check; not needed due to changes
+            to controlsAlwaysVisible().
+        (Controller.prototype.scheduleUpdateLayoutForDisplayedWidth): Moved from iOS.js.
+        (Controller.prototype.isControlVisible): Added; checks whether control is parented &amp; not hidden.
+        (Controller.prototype.updateLayoutForDisplayedWidth): Moved from iOS.js and refactored.
+        (Controller.prototype.controlsAlwaysVisible): Return true if scrubbing.
+        (Controller.prototype.updateHasAudio): Check currentPlaybackTargetIsWireless(); moved from iOS.js.
+        (Controller.prototype.get scrubbing): Simple getter for _scrubbing.
+        (Controller.prototype.set scrubbing): Check play state if scrubbing; start playback (if necessary)
+            if not scrubbing.
+        (Controller.prototype.get pageScaleFactor): Moved from iOS.js.
+        (Controller.prototype.set pageScaleFactor): Ditto.
+        (Controller.prototype.handleRootResize): Schedule an update of the contrtols width.
+
+        Remove a bunch of newly unnecessary code from the iOS media controls:
+
+        * Modules/mediacontrols/mediaControlsiOS.js:
+        (ControllerIOS):
+        (ControllerIOS.prototype.createControls): Remove ivars moved into Apple.js.
+        (ControllerIOS.prototype.configureInlineControls): Remove spacer; made unnecessary.
+        (ControllerIOS.prototype.showControls): Deleted.
+        (ControllerIOS.prototype.updateTime): Deleted.
+        (ControllerIOS.prototype.handleTimelineTouchStart): Just call &quot;scrubbing = true&quot;, handled in Apple.js.
+        (ControllerIOS.prototype.handleTimelineTouchEnd): Just call &quot;scrubbing = false&quot;, handled in Apple.js.
+        (ControllerIOS.prototype.handleReadyStateChange): Deleted.
+        (ControllerIOS.prototype.setPlaying): Don't check _timelineIsHidden; not needed.
+        (ControllerIOS.prototype.get pageScaleFactor): Deleted.
+        (ControllerIOS.prototype.set pageScaleFactor): Deleted.
+        (ControllerIOS.prototype.scheduleUpdateLayoutForDisplayedWidth): Deleted.
+        (ControllerIOS.prototypeupdateLayoutForDisplayedWidth): Deleted.
+
+        Fire a &quot;resize&quot; event at the shadow DOM root when layout results in a size change.
+
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::layoutSizeChanged): Fire the &quot;resize&quot; event at the shadow DOM.
+        * html/HTMLMediaElement.h:
+        * rendering/RenderMedia.cpp:
+        (WebCore::RenderMedia::layout): Trigger layoutSizeChanged()
+        * rendering/RenderMedia.h:
+
+        Drive-by fixes:
+
+        * Modules/mediacontrols/mediaControlsApple.js:
+        (Controller.prototype.createControls): aria-label text is totally wrong; removed.
+        (Controller.prototype.updateWirelessPlaybackStatus): Use class-names to hide controls, not inline styles.
+
</ins><span class="cx"> 2015-05-15  Alex Christensen  &lt;achristensen@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         [Content Extensions] Fail to load old content extension files
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmediacontrolsmediaControlsApplecss"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/mediacontrols/mediaControlsApple.css (184415 => 184416)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/mediacontrols/mediaControlsApple.css        2015-05-15 21:11:39 UTC (rev 184415)
+++ trunk/Source/WebCore/Modules/mediacontrols/mediaControlsApple.css        2015-05-15 21:30:18 UTC (rev 184416)
</span><span class="lines">@@ -598,7 +598,9 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> video::-webkit-media-controls-panel .hidden,
</span><del>-audio::-webkit-media-controls-panel .hidden {
</del><ins>+audio::-webkit-media-controls-panel .hidden,
+video::-webkit-media-controls-panel .dropped,
+audio::-webkit-media-controls-panel .dropped {
</ins><span class="cx">     display: none;
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmediacontrolsmediaControlsApplejs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/mediacontrols/mediaControlsApple.js (184415 => 184416)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/mediacontrols/mediaControlsApple.js        2015-05-15 21:11:39 UTC (rev 184415)
+++ trunk/Source/WebCore/Modules/mediacontrols/mediaControlsApple.js        2015-05-15 21:30:18 UTC (rev 184416)
</span><span class="lines">@@ -17,6 +17,9 @@
</span><span class="cx">     this.currentTargetIsWireless = false;
</span><span class="cx">     this.wirelessPlaybackDisabled = false;
</span><span class="cx">     this.isVolumeSliderActive = false;
</span><ins>+    this.currentDisplayWidth = 0;
+    this._scrubbing = false;
+    this._pageScaleFactor = 1;
</ins><span class="cx"> 
</span><span class="cx">     this.addVideoListeners();
</span><span class="cx">     this.createBase();
</span><span class="lines">@@ -37,6 +40,9 @@
</span><span class="cx">     this.updateHasVideo();
</span><span class="cx">     this.updateWirelessTargetAvailable();
</span><span class="cx">     this.updateWirelessPlaybackStatus();
</span><ins>+    this.scheduleUpdateLayoutForDisplayedWidth();
+
+    this.listenFor(this.root, 'resize', this.handleRootResize);
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> /* Enums */
</span><span class="lines">@@ -81,6 +87,7 @@
</span><span class="cx">     SeekDelay: 1500,
</span><span class="cx">     ClassNames: {
</span><span class="cx">         active: 'active',
</span><ins>+        dropped: 'dropped',
</ins><span class="cx">         exit: 'exit',
</span><span class="cx">         failed: 'failed',
</span><span class="cx">         hidden: 'hidden',
</span><span class="lines">@@ -118,6 +125,8 @@
</span><span class="cx">         right: 39,
</span><span class="cx">         down: 40
</span><span class="cx">     },
</span><ins>+    MinimumTimelineWidth: 150,
+    ButtonWidth: 32,
</ins><span class="cx"> 
</span><span class="cx">     extend: function(child)
</span><span class="cx">     {
</span><span class="lines">@@ -457,8 +466,7 @@
</span><span class="cx">         inlinePlaybackPlaceholder.setAttribute('pseudo', '-webkit-media-controls-wireless-playback-status');
</span><span class="cx">         if (!Controller.gSimulateOptimizedFullscreenAvailable)
</span><span class="cx">             inlinePlaybackPlaceholder.classList.add(this.ClassNames.hidden);
</span><del>-        inlinePlaybackPlaceholder.setAttribute('aria-label', this.UIString('Display Optimized Full Screen'));
-        
</del><ins>+
</ins><span class="cx">         var inlinePlaybackPlaceholderText = this.controls.inlinePlaybackPlaceholderText = document.createElement('div');
</span><span class="cx">         inlinePlaybackPlaceholderText.setAttribute('pseudo', '-webkit-media-controls-wireless-playback-text');
</span><span class="cx">         
</span><span class="lines">@@ -593,6 +601,8 @@
</span><span class="cx">         else
</span><span class="cx">             this.setControlsType(Controller.InlineControls);
</span><span class="cx"> 
</span><ins>+        this.setNeedsUpdateForDisplayedWidth();
+        this.updateLayoutForDisplayedWidth();
</ins><span class="cx">         this.setNeedsTimelineMetricsUpdate();
</span><span class="cx">     },
</span><span class="cx"> 
</span><span class="lines">@@ -657,12 +667,15 @@
</span><span class="cx">         this.updateFullscreenButtons();
</span><span class="cx">         this.updateWirelessTargetPickerButton();
</span><span class="cx">         this.updateProgress();
</span><ins>+        this.updateControls();
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     handleTimeUpdate: function(event)
</span><span class="cx">     {
</span><del>-        if (!this.scrubbing)
</del><ins>+        if (!this.scrubbing) {
</ins><span class="cx">             this.updateTime();
</span><ins>+            this.updateProgress();
+        }
</ins><span class="cx">         this.drawTimelineBackground();
</span><span class="cx">     },
</span><span class="cx"> 
</span><span class="lines">@@ -851,6 +864,9 @@
</span><span class="cx"> 
</span><span class="cx">     handleTimelineInput: function(event)
</span><span class="cx">     {
</span><ins>+        if (this.scrubbing)
+            this.video.pause();
+
</ins><span class="cx">         this.video.fastSeek(this.controls.timeline.value);
</span><span class="cx">         this.updateControlsWhileScrubbing();
</span><span class="cx">     },
</span><span class="lines">@@ -858,6 +874,7 @@
</span><span class="cx">     handleTimelineChange: function(event)
</span><span class="cx">     {
</span><span class="cx">         this.video.currentTime = this.controls.timeline.value;
</span><ins>+        this.updateProgress();
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     handleTimelineDown: function(event)
</span><span class="lines">@@ -995,6 +1012,8 @@
</span><span class="cx">         var shouldBeHidden = !this.video.webkitSupportsFullscreen || !this.hasVideo();
</span><span class="cx">         this.controls.fullscreenButton.classList.toggle(this.ClassNames.hidden, shouldBeHidden);
</span><span class="cx">         this.controls.optimizedFullscreenButton.classList.toggle(this.ClassNames.hidden, shouldBeHidden);
</span><ins>+        this.setNeedsUpdateForDisplayedWidth();
+        this.updateLayoutForDisplayedWidth();
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     handleFullscreenButtonClicked: function(event)
</span><span class="lines">@@ -1346,6 +1365,7 @@
</span><span class="cx">         if (this.showInlinePlaybackPlaceholderOnly())
</span><span class="cx">             return;
</span><span class="cx"> 
</span><ins>+        this.updateLayoutForDisplayedWidth();
</ins><span class="cx">         this.setNeedsTimelineMetricsUpdate();
</span><span class="cx">         this.updateTime(true);
</span><span class="cx">         this.updateProgress(true);
</span><span class="lines">@@ -1362,7 +1382,7 @@
</span><span class="cx"> 
</span><span class="cx">     hideControls: function()
</span><span class="cx">     {
</span><del>-        if (this.controlsAlwaysVisible() || this._potentiallyScrubbing)
</del><ins>+        if (this.controlsAlwaysVisible())
</ins><span class="cx">             return;
</span><span class="cx"> 
</span><span class="cx">         this.updateShouldListenForPlaybackTargetAvailabilityEvent();
</span><span class="lines">@@ -1371,9 +1391,66 @@
</span><span class="cx">             this.controls.panelBackground.classList.remove(this.ClassNames.show);
</span><span class="cx">     },
</span><span class="cx"> 
</span><ins>+    setNeedsUpdateForDisplayedWidth: function()
+    {
+        this.currentDisplayWidth = 0;
+    },
+
+    scheduleUpdateLayoutForDisplayedWidth: function()
+    {
+        setTimeout(this.updateLayoutForDisplayedWidth.bind(this), 0);
+    },
+
+    isControlVisible: function(control)
+    {
+        if (!control)
+            return false;
+        if (!this.root.contains(control))
+            return false;
+        return !control.classList.contains(this.ClassNames.hidden)
+    },
+
+    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;
+
+        // Filter all the buttons which are not explicitly hidden.
+        var buttons = [this.controls.playButton, this.controls.rewindButton, this.controls.captionButton,
+                       this.controls.fullscreenButton, this.controls.optimizedFullscreenButton,
+                       this.controls.wirelessTargetPicker, this.controls.muteBox];
+        var visibleButtons = buttons.filter(this.isControlVisible, this);
+
+        // This tells us how much room we need in order to display every visible button.
+        var visibleButtonWidth = this.ButtonWidth * visibleButtons.length;
+
+        // Check if there is enough room for the scrubber.
+        var shouldDropTimeline = (visibleWidth - visibleButtonWidth) &lt; this.MinimumTimelineWidth;
+        this.controls.currentTime.classList.toggle(this.ClassNames.dropped, shouldDropTimeline);
+        this.controls.thumbnailTrack.classList.toggle(this.ClassNames.dropped, shouldDropTimeline);
+        this.controls.remainingTime.classList.toggle(this.ClassNames.dropped, shouldDropTimeline);
+
+        // Then controls in the following order:
+        var removeOrder = [this.controls.wirelessTargetPicker, this.controls.optimizedFullscreenButton,
+                           this.controls.captionButton, this.controls.muteBox, this.controls.rewindButton,
+                           this.controls.fullscreenButton];
+        removeOrder.forEach(function(control) {
+            var shouldDropControl = visibleWidth &lt; visibleButtonWidth &amp;&amp; this.isControlVisible(control);
+            control.classList.toggle(this.ClassNames.dropped, shouldDropControl);
+            if (shouldDropControl)
+                visibleButtonWidth -= this.ButtonWidth;
+        }, this);
+    },
+
</ins><span class="cx">     controlsAlwaysVisible: function()
</span><span class="cx">     {
</span><del>-        return this.isAudio() || this.currentPlaybackTargetIsWireless();
</del><ins>+        return this.isAudio() || this.currentPlaybackTargetIsWireless() || this.scrubbing;
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     controlsAreHidden: function()
</span><span class="lines">@@ -1472,6 +1549,8 @@
</span><span class="cx">             this.controls.captionButton.classList.remove(this.ClassNames.hidden);
</span><span class="cx">         else
</span><span class="cx">             this.controls.captionButton.classList.add(this.ClassNames.hidden);
</span><ins>+        this.setNeedsUpdateForDisplayedWidth();
+        this.updateLayoutForDisplayedWidth();
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     updateCaptionContainer: function()
</span><span class="lines">@@ -1737,10 +1816,13 @@
</span><span class="cx"> 
</span><span class="cx">     updateHasAudio: function()
</span><span class="cx">     {
</span><del>-        if (this.video.audioTracks.length)
</del><ins>+        if (this.video.audioTracks.length &amp;&amp; !this.currentPlaybackTargetIsWireless())
</ins><span class="cx">             this.controls.muteBox.classList.remove(this.ClassNames.hidden);
</span><span class="cx">         else
</span><span class="cx">             this.controls.muteBox.classList.add(this.ClassNames.hidden);
</span><ins>+
+        this.setNeedsUpdateForDisplayedWidth();
+        this.updateLayoutForDisplayedWidth();
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     updateHasVideo: function()
</span><span class="lines">@@ -1837,20 +1919,18 @@
</span><span class="cx">                 this.controls.inlinePlaybackPlaceholderTextTop.classList.remove(this.ClassNames.small);
</span><span class="cx">                 this.controls.inlinePlaybackPlaceholderTextBottom.classList.remove(this.ClassNames.small);
</span><span class="cx">             }
</span><del>-            if (this.isFullScreen())
-                this.controls.volumeBox.style.display = &quot;none&quot;;
-            else
-                this.controls.muteBox.style.display = &quot;none&quot;;
</del><ins>+            this.controls.volumeBox.classList.add(this.ClassNames.hidden);
+            this.controls.muteBox.classList.add(this.ClassNames.hidden);
</ins><span class="cx">             this.updateBase();
</span><span class="cx">             this.showControls();
</span><span class="cx">         } else {
</span><span class="cx">             this.controls.inlinePlaybackPlaceholder.classList.add(this.ClassNames.hidden);
</span><span class="cx">             this.controls.wirelessTargetPicker.classList.remove(this.ClassNames.playing);
</span><del>-            if (this.isFullScreen())
-                this.controls.volumeBox.style.display = &quot;-webkit-flex&quot;;
-            else
-                this.controls.muteBox.style.display = &quot;-webkit-flex&quot;;
</del><ins>+            this.controls.volumeBox.classList.remove(this.ClassNames.hidden);
+            this.controls.muteBox.classList.remove(this.ClassNames.hidden);
</ins><span class="cx">         }
</span><ins>+        this.setNeedsUpdateForDisplayedWidth();
+        this.updateLayoutForDisplayedWidth();
</ins><span class="cx">         this.updateWirelessTargetPickerButton();
</span><span class="cx">     },
</span><span class="cx"> 
</span><span class="lines">@@ -1866,6 +1946,8 @@
</span><span class="cx">             this.controls.wirelessTargetPicker.classList.remove(this.ClassNames.hidden);
</span><span class="cx">         else
</span><span class="cx">             this.controls.wirelessTargetPicker.classList.add(this.ClassNames.hidden);
</span><ins>+        this.setNeedsUpdateForDisplayedWidth();
+        this.updateLayoutForDisplayedWidth();
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     handleWirelessPickerButtonClicked: function(event)
</span><span class="lines">@@ -1911,4 +1993,50 @@
</span><span class="cx">         return this.currentPlaybackTargetIsWireless() &amp;&amp; !this.video.controls;
</span><span class="cx">     },
</span><span class="cx"> 
</span><ins>+    get scrubbing()
+    {
+        return this._scrubbing;
+    },
+
+    set scrubbing(flag)
+    {
+        if (this._scrubbing == flag)
+            return;
+        this._scrubbing = flag;
+
+        if (this._scrubbing)
+            this.wasPlayingWhenScrubbingStarted = !this.video.paused;
+        else if (this.wasPlayingWhenScrubbingStarted &amp;&amp; this.video.paused) {
+            this.video.play();
+            this.resetHideControlsTimer();
+        }
+    },
+
+    get pageScaleFactor()
+    {
+        return this._pageScaleFactor;
+    },
+
+    set pageScaleFactor(newScaleFactor)
+    {
+        if (this._pageScaleFactor === newScaleFactor)
+            return;
+
+        this._pageScaleFactor = newScaleFactor;
+
+        // FIXME: this should react to the scale change by
+        // unscaling the controls panel. However, this
+        // hits a bug with the backdrop blur layer getting
+        // too big and moving to a tiled layer.
+        // https://bugs.webkit.org/show_bug.cgi?id=142317
+    },
+
+    handleRootResize: function(event)
+    {
+        this.updateLayoutForDisplayedWidth();
+        this.setNeedsTimelineMetricsUpdate();
+        this.updateTimelineMetricsIfNeeded();
+        this.drawTimelineBackground();
+    }
+
</ins><span class="cx"> };
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmediacontrolsmediaControlsiOSjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/mediacontrols/mediaControlsiOS.js (184415 => 184416)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/mediacontrols/mediaControlsiOS.js        2015-05-15 21:11:39 UTC (rev 184415)
+++ trunk/Source/WebCore/Modules/mediacontrols/mediaControlsiOS.js        2015-05-15 21:30:18 UTC (rev 184416)
</span><span class="lines">@@ -16,22 +16,21 @@
</span><span class="cx"> 
</span><span class="cx">     this._timelineIsHidden = false;
</span><span class="cx">     this._currentDisplayWidth = 0;
</span><del>-    this._potentiallyScrubbing = false;
</del><span class="cx">     this.scheduleUpdateLayoutForDisplayedWidth();
</span><span class="cx"> 
</span><span class="cx">     host.controlsDependOnPageScaleFactor = true;
</span><span class="cx">     this.doingSetup = false;
</span><span class="cx"> };
</span><span class="cx"> 
</span><del>-/* Constants */
-ControllerIOS.MinimumTimelineWidth = 200;
-ControllerIOS.ButtonWidth = 42;
-
</del><span class="cx"> /* Enums */
</span><span class="cx"> ControllerIOS.StartPlaybackControls = 2;
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> ControllerIOS.prototype = {
</span><ins>+    /* Constants */
+    MinimumTimelineWidth: 200,
+    ButtonWidth: 42,
+
</ins><span class="cx">     addVideoListeners: function() {
</span><span class="cx">         Controller.prototype.addVideoListeners.call(this);
</span><span class="cx"> 
</span><span class="lines">@@ -112,10 +111,6 @@
</span><span class="cx">         var panelBackground = this.controls.panelBackground = document.createElement('div');
</span><span class="cx">         panelBackground.setAttribute('pseudo', '-webkit-media-controls-panel-background');
</span><span class="cx"> 
</span><del>-        var spacer = this.controls.spacer = document.createElement('div');
-        spacer.setAttribute('pseudo', '-webkit-media-controls-spacer');
-        spacer.classList.add(this.ClassNames.hidden);
-
</del><span class="cx">         var inlinePlaybackPlaceholderText = this.controls.inlinePlaybackPlaceholderText = document.createElement('div');
</span><span class="cx">         inlinePlaybackPlaceholderText.setAttribute('pseudo', '-webkit-media-controls-wireless-playback-text');
</span><span class="cx"> 
</span><span class="lines">@@ -186,7 +181,6 @@
</span><span class="cx">         this.controls.inlinePlaybackPlaceholderText.appendChild(this.controls.inlinePlaybackPlaceholderTextBottom);
</span><span class="cx">         this.controls.panel.appendChild(this.controls.playButton);
</span><span class="cx">         this.controls.panel.appendChild(this.controls.statusDisplay);
</span><del>-        this.controls.panel.appendChild(this.controls.spacer);
</del><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">@@ -208,13 +202,6 @@
</span><span class="cx">         // Explicitly do nothing to override base-class behavior.
</span><span class="cx">     },
</span><span class="cx"> 
</span><del>-    showControls: function() {
-        this.updateLayoutForDisplayedWidth();
-        this.updateTime(true);
-        this.updateProgress(true);
-        Controller.prototype.showControls.call(this);
-    },
-
</del><span class="cx">     addControls: function() {
</span><span class="cx">         this.base.appendChild(this.controls.inlinePlaybackPlaceholder);
</span><span class="cx">         this.base.appendChild(this.controls.panelContainer);
</span><span class="lines">@@ -235,11 +222,6 @@
</span><span class="cx">         this.setNeedsTimelineMetricsUpdate();
</span><span class="cx">     },
</span><span class="cx"> 
</span><del>-    updateTime: function(forceUpdate) {
-        Controller.prototype.updateTime.call(this, forceUpdate);
-        this.updateProgress();
-    },
-
</del><span class="cx">     drawTimelineBackground: function() {
</span><span class="cx">         var width = this.timelineWidth * window.devicePixelRatio;
</span><span class="cx">         var height = this.timelineHeight * window.devicePixelRatio;
</span><span class="lines">@@ -493,20 +475,8 @@
</span><span class="cx">         return true;
</span><span class="cx">     },
</span><span class="cx"> 
</span><del>-    handleTimelineInput: function(event) {
-        if (this._potentiallyScrubbing)
-            this.video.pause();
-        Controller.prototype.handleTimelineInput.call(this, event);
-    },
-
-    handleTimelineChange: function(event) {
-        Controller.prototype.handleTimelineChange.call(this, event);
-        this.updateProgress();
-    },
-
</del><span class="cx">     handleTimelineTouchStart: function(event) {
</span><del>-        this._potentiallyScrubbing = true;
-        this.wasPlayingWhenScrubbingStarted = !this.video.paused;
</del><ins>+        this.scrubbing = true;
</ins><span class="cx">         this.listenFor(this.controls.timeline, 'touchend', this.handleTimelineTouchEnd);
</span><span class="cx">         this.listenFor(this.controls.timeline, 'touchcancel', this.handleTimelineTouchEnd);
</span><span class="cx">     },
</span><span class="lines">@@ -514,18 +484,9 @@
</span><span class="cx">     handleTimelineTouchEnd: function(event) {
</span><span class="cx">         this.stopListeningFor(this.controls.timeline, 'touchend', this.handleTimelineTouchEnd);
</span><span class="cx">         this.stopListeningFor(this.controls.timeline, 'touchcancel', this.handleTimelineTouchEnd);
</span><del>-        this._potentiallyScrubbing = false;
-        if (this.wasPlayingWhenScrubbingStarted &amp;&amp; this.video.paused) {
-            this.video.play();
-            this.resetHideControlsTimer();
-        }
</del><ins>+        this.scrubbing = false;
</ins><span class="cx">     },
</span><span class="cx"> 
</span><del>-    handleReadyStateChange: function(event) {
-        Controller.prototype.handleReadyStateChange.call(this, event);
-        this.updateControls();
-    },
-
</del><span class="cx">     handleWirelessPickerButtonTouchStart: function() {
</span><span class="cx">         if (!this.video.error)
</span><span class="cx">             this.controls.wirelessTargetPicker.classList.add('active');
</span><span class="lines">@@ -562,10 +523,8 @@
</span><span class="cx"> 
</span><span class="cx">         this.updateControls();
</span><span class="cx"> 
</span><del>-        if (isPlaying &amp;&amp; this.isAudio() &amp;&amp; !this._timelineIsHidden) {
</del><ins>+        if (isPlaying &amp;&amp; this.isAudio())
</ins><span class="cx">             this.controls.timelineBox.classList.remove(this.ClassNames.hidden);
</span><del>-            this.controls.spacer.classList.add(this.ClassNames.hidden);
-        }
</del><span class="cx"> 
</span><span class="cx">         if (isPlaying)
</span><span class="cx">             this.hasPlayed = true;
</span><span class="lines">@@ -581,25 +540,6 @@
</span><span class="cx">         Controller.prototype.setShouldListenForPlaybackTargetAvailabilityEvent.call(this, shouldListen);
</span><span class="cx">     },
</span><span class="cx"> 
</span><del>-    get pageScaleFactor()
-    {
-        return this._pageScaleFactor;
-    },
-
-    set pageScaleFactor(newScaleFactor)
-    {
-        if (this._pageScaleFactor === newScaleFactor)
-            return;
-
-        this._pageScaleFactor = newScaleFactor;
-
-        // FIXME: this should react to the scale change by
-        // unscaling the controls panel. However, this
-        // hits a bug with the backdrop blur layer getting
-        // too big and moving to a tiled layer.
-        // https://bugs.webkit.org/show_bug.cgi?id=142317
-    },
-
</del><span class="cx">     handlePresentationModeChange: function(event)
</span><span class="cx">     {
</span><span class="cx">         var presentationMode = this.presentationMode();
</span><span class="lines">@@ -628,69 +568,6 @@
</span><span class="cx">         this.handlePresentationModeChange(event);
</span><span class="cx">     },
</span><span class="cx"> 
</span><del>-    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);
-    },
-
</del><span class="cx">     controlsAlwaysVisible: function()
</span><span class="cx">     {
</span><span class="cx">         if (this.presentationMode() === 'optimized')
</span></span></pre></div>
<a id="trunkSourceWebCorehtmlHTMLMediaElementcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/html/HTMLMediaElement.cpp (184415 => 184416)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/HTMLMediaElement.cpp        2015-05-15 21:11:39 UTC (rev 184415)
+++ trunk/Source/WebCore/html/HTMLMediaElement.cpp        2015-05-15 21:30:18 UTC (rev 184416)
</span><span class="lines">@@ -261,6 +261,8 @@
</span><span class="cx">     , m_playbackProgressTimer(*this, &amp;HTMLMediaElement::playbackProgressTimerFired)
</span><span class="cx">     , m_scanTimer(*this, &amp;HTMLMediaElement::scanTimerFired)
</span><span class="cx">     , m_seekTaskQueue(document)
</span><ins>+    , m_resizeTaskQueue(document)
+    , m_shadowDOMTaskQueue(document)
</ins><span class="cx">     , m_playedTimeRanges()
</span><span class="cx">     , m_asyncEventQueue(*this)
</span><span class="cx">     , m_requestedPlaybackRate(1)
</span><span class="lines">@@ -3776,6 +3778,18 @@
</span><span class="cx">     exec-&gt;clearException();
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><ins>+
+void HTMLMediaElement::layoutSizeChanged()
+{
+#if ENABLE(MEDIA_CONTROLS_SCRIPT)
+    RefPtr&lt;HTMLMediaElement&gt; strongThis = this;
+    std::function&lt;void()&gt; task = [strongThis] {
+        if (ShadowRoot* root = strongThis-&gt;userAgentShadowRoot())
+            root-&gt;dispatchEvent(Event::create(&quot;resize&quot;, false, false));
+    };
+    m_resizeTaskQueue.enqueueTask(task);
+#endif
+}
</ins><span class="cx">     
</span><span class="cx"> void HTMLMediaElement::setSelectedTextTrack(TextTrack* trackToSelect)
</span><span class="cx"> {
</span><span class="lines">@@ -5707,7 +5721,6 @@
</span><span class="cx">         return String();
</span><span class="cx"> 
</span><span class="cx">     return frame-&gt;loader().userAgent(m_currentSrc);
</span><del>-
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(AVF_CAPTIONS)
</span><span class="lines">@@ -6002,6 +6015,7 @@
</span><span class="cx"> void HTMLMediaElement::didAddUserAgentShadowRoot(ShadowRoot* root)
</span><span class="cx"> {
</span><span class="cx">     LOG(Media, &quot;HTMLMediaElement::didAddUserAgentShadowRoot(%p)&quot;, this);
</span><ins>+
</ins><span class="cx">     Page* page = document().page();
</span><span class="cx">     if (!page)
</span><span class="cx">         return;
</span></span></pre></div>
<a id="trunkSourceWebCorehtmlHTMLMediaElementh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/html/HTMLMediaElement.h (184415 => 184416)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/HTMLMediaElement.h        2015-05-15 21:11:39 UTC (rev 184415)
+++ trunk/Source/WebCore/html/HTMLMediaElement.h        2015-05-15 21:30:18 UTC (rev 184416)
</span><span class="lines">@@ -459,6 +459,8 @@
</span><span class="cx"> 
</span><span class="cx">     virtual MediaProducer::MediaStateFlags mediaState() const override;
</span><span class="cx"> 
</span><ins>+    void layoutSizeChanged();
+
</ins><span class="cx"> protected:
</span><span class="cx">     HTMLMediaElement(const QualifiedName&amp;, Document&amp;, bool);
</span><span class="cx">     virtual ~HTMLMediaElement();
</span><span class="lines">@@ -748,6 +750,8 @@
</span><span class="cx">     Timer m_playbackProgressTimer;
</span><span class="cx">     Timer m_scanTimer;
</span><span class="cx">     GenericTaskQueue&lt;ScriptExecutionContext&gt; m_seekTaskQueue;
</span><ins>+    GenericTaskQueue&lt;ScriptExecutionContext&gt; m_resizeTaskQueue;
+    GenericTaskQueue&lt;ScriptExecutionContext&gt; m_shadowDOMTaskQueue;
</ins><span class="cx">     RefPtr&lt;TimeRanges&gt; m_playedTimeRanges;
</span><span class="cx">     GenericEventQueue m_asyncEventQueue;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderMediacpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderMedia.cpp (184415 => 184416)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderMedia.cpp        2015-05-15 21:11:39 UTC (rev 184415)
+++ trunk/Source/WebCore/rendering/RenderMedia.cpp        2015-05-15 21:30:18 UTC (rev 184416)
</span><span class="lines">@@ -55,6 +55,15 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void RenderMedia::layout()
+{
+    LayoutSize oldSize = size();
+    RenderImage::layout();
+    if (oldSize != size())
+        mediaElement().layoutSizeChanged();
+}
+
+
</ins><span class="cx"> } // namespace WebCore
</span><span class="cx"> 
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderMediah"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderMedia.h (184415 => 184416)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderMedia.h        2015-05-15 21:11:39 UTC (rev 184415)
+++ trunk/Source/WebCore/rendering/RenderMedia.h        2015-05-15 21:30:18 UTC (rev 184416)
</span><span class="lines">@@ -41,6 +41,9 @@
</span><span class="cx"> 
</span><span class="cx">     HTMLMediaElement&amp; mediaElement() const { return downcast&lt;HTMLMediaElement&gt;(nodeForNonAnonymous()); }
</span><span class="cx"> 
</span><ins>+protected:
+    virtual void layout() override;
+
</ins><span class="cx"> private:
</span><span class="cx">     void element() const = delete;
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>