<!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>[206454] 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/206454">206454</a></dd>
<dt>Author</dt> <dd>wenson_hsieh@apple.com</dd>
<dt>Date</dt> <dd>2016-09-27 12:39:45 -0700 (Tue, 27 Sep 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Related videos on YouTube (and YouTube playlists) cause media controls to disappear
https://bugs.webkit.org/show_bug.cgi?id=162621
&lt;rdar://problem/28484193&gt;

Reviewed by Jer Noble.

Tweaks the main content media heuristic for better Now Playing behavior on YouTube by making the following
changes:
- Remove the strict requirement for audio to be actively playing for the session to be able to show
  controls for the purpose of Now Playing, making it the same as our policy for the controls manager.
- Make playback requirement restrictions apply only for the controls manager. Videos that do not
  autoplay will still have the correct behavior with respect to Now Playing, since we will bail in the
  hasEverNotifiedAboutPlaying() check.
- Only consider the main content heuristic as preventing media controls from showing up for the purposes
  of the controls manager. Now Playing should instead account for this by preferring elements large
  enough for main content after collecting all of the candidate sessions.

* html/HTMLMediaElement.cpp:
(WebCore::mediaElementSessionInfoForSession):
(WebCore::preferMediaControlsForCandidateSessionOverOtherCandidateSession):
(WebCore::HTMLMediaElement::updatePlayState):
* html/MediaElementSession.cpp:
(WebCore::MediaElementSession::canShowControlsManager):
* platform/audio/mac/MediaSessionManagerMac.mm:
(WebCore::MediaSessionManagerMac::sessionWillBeginPlayback):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorehtmlHTMLMediaElementcpp">trunk/Source/WebCore/html/HTMLMediaElement.cpp</a></li>
<li><a href="#trunkSourceWebCorehtmlMediaElementSessioncpp">trunk/Source/WebCore/html/MediaElementSession.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformaudiomacMediaSessionManagerMacmm">trunk/Source/WebCore/platform/audio/mac/MediaSessionManagerMac.mm</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (206453 => 206454)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-09-27 19:35:49 UTC (rev 206453)
+++ trunk/Source/WebCore/ChangeLog        2016-09-27 19:39:45 UTC (rev 206454)
</span><span class="lines">@@ -1,3 +1,31 @@
</span><ins>+2016-09-27  Wenson Hsieh  &lt;wenson_hsieh@apple.com&gt;
+
+        Related videos on YouTube (and YouTube playlists) cause media controls to disappear
+        https://bugs.webkit.org/show_bug.cgi?id=162621
+        &lt;rdar://problem/28484193&gt;
+
+        Reviewed by Jer Noble.
+
+        Tweaks the main content media heuristic for better Now Playing behavior on YouTube by making the following
+        changes:
+        - Remove the strict requirement for audio to be actively playing for the session to be able to show
+          controls for the purpose of Now Playing, making it the same as our policy for the controls manager.
+        - Make playback requirement restrictions apply only for the controls manager. Videos that do not
+          autoplay will still have the correct behavior with respect to Now Playing, since we will bail in the
+          hasEverNotifiedAboutPlaying() check.
+        - Only consider the main content heuristic as preventing media controls from showing up for the purposes
+          of the controls manager. Now Playing should instead account for this by preferring elements large
+          enough for main content after collecting all of the candidate sessions.
+
+        * html/HTMLMediaElement.cpp:
+        (WebCore::mediaElementSessionInfoForSession):
+        (WebCore::preferMediaControlsForCandidateSessionOverOtherCandidateSession):
+        (WebCore::HTMLMediaElement::updatePlayState):
+        * html/MediaElementSession.cpp:
+        (WebCore::MediaElementSession::canShowControlsManager):
+        * platform/audio/mac/MediaSessionManagerMac.mm:
+        (WebCore::MediaSessionManagerMac::sessionWillBeginPlayback):
+
</ins><span class="cx"> 2016-09-27  Chris Dumez  &lt;cdumez@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Second parameter to MutationObserver.observe() should be optional
</span></span></pre></div>
<a id="trunkSourceWebCorehtmlHTMLMediaElementcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/html/HTMLMediaElement.cpp (206453 => 206454)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/HTMLMediaElement.cpp        2016-09-27 19:35:49 UTC (rev 206453)
+++ trunk/Source/WebCore/html/HTMLMediaElement.cpp        2016-09-27 19:39:45 UTC (rev 206454)
</span><span class="lines">@@ -332,6 +332,7 @@
</span><span class="cx"> 
</span><span class="cx"> struct MediaElementSessionInfo {
</span><span class="cx">     const MediaElementSession* session;
</span><ins>+    MediaElementSession::PlaybackControlsPurpose purpose;
</ins><span class="cx"> 
</span><span class="cx">     double timeOfLastUserInteraction;
</span><span class="cx">     bool canShowControlsManager : 1;
</span><span class="lines">@@ -345,6 +346,7 @@
</span><span class="cx">     const HTMLMediaElement&amp; element = session.element();
</span><span class="cx">     return {
</span><span class="cx">         &amp;session,
</span><ins>+        purpose,
</ins><span class="cx">         session.mostRecentUserInteractionTime(),
</span><span class="cx">         session.canShowControlsManager(purpose),
</span><span class="cx">         element.isFullscreen() || element.isVisibleInViewport(),
</span><span class="lines">@@ -355,10 +357,17 @@
</span><span class="cx"> 
</span><span class="cx"> static bool preferMediaControlsForCandidateSessionOverOtherCandidateSession(const MediaElementSessionInfo&amp; session, const MediaElementSessionInfo&amp; otherSession)
</span><span class="cx"> {
</span><del>-    // Prioritize visible media over offscreen media.
-    if (session.isVisibleInViewportOrFullscreen != otherSession.isVisibleInViewportOrFullscreen)
</del><ins>+    MediaElementSession::PlaybackControlsPurpose purpose = session.purpose;
+    ASSERT(purpose == otherSession.purpose);
+
+    // For the controls manager, prioritize visible media over offscreen media.
+    if (purpose == MediaElementSession::PlaybackControlsPurpose::ControlsManager &amp;&amp; session.isVisibleInViewportOrFullscreen != otherSession.isVisibleInViewportOrFullscreen)
</ins><span class="cx">         return session.isVisibleInViewportOrFullscreen;
</span><span class="cx"> 
</span><ins>+    // For Now Playing, prioritize elements that would normally satisfy main content.
+    if (purpose == MediaElementSession::PlaybackControlsPurpose::NowPlaying &amp;&amp; session.isLargeEnoughForMainContent != otherSession.isLargeEnoughForMainContent)
+        return session.isLargeEnoughForMainContent;
+
</ins><span class="cx">     // As a tiebreaker, prioritize elements that the user recently interacted with.
</span><span class="cx">     return session.timeOfLastUserInteraction &gt; otherSession.timeOfLastUserInteraction;
</span><span class="cx"> }
</span><span class="lines">@@ -5013,6 +5022,9 @@
</span><span class="cx">     
</span><span class="cx">     updateMediaController();
</span><span class="cx">     updateRenderer();
</span><ins>+
+    m_hasEverHadAudio |= hasAudio();
+    m_hasEverHadVideo |= hasVideo();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void HTMLMediaElement::setPlaying(bool playing)
</span></span></pre></div>
<a id="trunkSourceWebCorehtmlMediaElementSessioncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/html/MediaElementSession.cpp (206453 => 206454)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/MediaElementSession.cpp        2016-09-27 19:35:49 UTC (rev 206453)
+++ trunk/Source/WebCore/html/MediaElementSession.cpp        2016-09-27 19:39:45 UTC (rev 206454)
</span><span class="lines">@@ -233,8 +233,7 @@
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    bool meetsAudioTrackRequirements = m_element.hasAudio() || (purpose == PlaybackControlsPurpose::ControlsManager &amp;&amp; m_element.hasEverHadAudio());
-    if (!meetsAudioTrackRequirements) {
</del><ins>+    if (!m_element.hasAudio() &amp;&amp; !m_element.hasEverHadAudio()) {
</ins><span class="cx">         LOG(Media, &quot;MediaElementSession::canShowControlsManager - returning FALSE: No audio&quot;);
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="lines">@@ -259,7 +258,7 @@
</span><span class="cx">         return true;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (hasBehaviorRestriction(RequirePlaybackToControlControlsManager) &amp;&amp; !m_element.isPlaying()) {
</del><ins>+    if (purpose == PlaybackControlsPurpose::ControlsManager &amp;&amp; hasBehaviorRestriction(RequirePlaybackToControlControlsManager) &amp;&amp; !m_element.isPlaying()) {
</ins><span class="cx">         LOG(Media, &quot;MediaElementSession::canShowControlsManager - returning FALSE: Needs to be playing&quot;);
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="lines">@@ -274,13 +273,14 @@
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (m_element.isVideo()) {
</del><ins>+    // Only allow the main content heuristic to forbid videos from showing up if our purpose is the controls manager.
+    if (purpose == PlaybackControlsPurpose::ControlsManager &amp;&amp; m_element.isVideo()) {
</ins><span class="cx">         if (!m_element.renderer()) {
</span><span class="cx">             LOG(Media, &quot;MediaElementSession::canShowControlsManager - returning FALSE: No renderer&quot;);
</span><span class="cx">             return false;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (purpose == PlaybackControlsPurpose::ControlsManager &amp;&amp; !m_element.hasVideo() &amp;&amp; !m_element.hasEverHadVideo()) {
</del><ins>+        if (!m_element.hasVideo() &amp;&amp; !m_element.hasEverHadVideo()) {
</ins><span class="cx">             LOG(Media, &quot;MediaElementSession::canShowControlsManager - returning FALSE: No video&quot;);
</span><span class="cx">             return false;
</span><span class="cx">         }
</span><span class="lines">@@ -291,6 +291,11 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    if (purpose == PlaybackControlsPurpose::NowPlaying) {
+        LOG(Media, &quot;MediaElementSession::canShowControlsManager - returning TRUE: Potentially plays audio&quot;);
+        return true;
+    }
+
</ins><span class="cx">     LOG(Media, &quot;MediaElementSession::canShowControlsManager - returning FALSE: No user gesture&quot;);
</span><span class="cx">     return false;
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformaudiomacMediaSessionManagerMacmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/audio/mac/MediaSessionManagerMac.mm (206453 => 206454)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/audio/mac/MediaSessionManagerMac.mm        2016-09-27 19:35:49 UTC (rev 206453)
+++ trunk/Source/WebCore/platform/audio/mac/MediaSessionManagerMac.mm        2016-09-27 19:39:45 UTC (rev 206454)
</span><span class="lines">@@ -81,7 +81,7 @@
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><span class="cx">     LOG(Media, &quot;MediaSessionManagerMac::sessionWillBeginPlayback&quot;);
</span><del>-    updateNowPlayingInfo();
</del><ins>+    scheduleUpdateNowPlayingInfo();
</ins><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>