<!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>[214721] 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/214721">214721</a></dd>
<dt>Author</dt> <dd>cdumez@apple.com</dd>
<dt>Date</dt> <dd>2017-04-01 17:55:20 -0700 (Sat, 01 Apr 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>We should pause silent WebAudio rendering in background tabs
https://bugs.webkit.org/show_bug.cgi?id=170299
&lt;rdar://problem/31289132&gt;

Reviewed by Eric Carlson.

Source/WebCore:

We should pause silent WebAudio rendering in background tabs since it uses CPU and is
not observable by the user. Such silent WebAudio rendering seems to be used by
doubleclick ads.

Test: webaudio/silent-audio-interrupted-in-background.html

* Modules/webaudio/AudioContext.cpp:
(WebCore::AudioContext::lazyInitialize):
(WebCore::AudioContext::uninitialize):
Have AudioContext register / unregister itself with the Document to get
visibility change notifications, similarly to what HTMLMediaElement was
already doing.

(WebCore::AudioContext::visibilityStateChanged):
Begin / End session interruption whenever the page visiblity changes.

* Modules/webaudio/AudioContext.h:
* WebCore.xcodeproj/project.pbxproj:

* dom/Document.cpp:
(WebCore::Document::registerForVisibilityStateChangedCallbacks):
(WebCore::Document::unregisterForVisibilityStateChangedCallbacks):
(WebCore::Document::visibilityStateChanged):
* dom/Document.h:
* dom/Element.h:
* dom/VisibilityChangeClient.h: Added.
(WebCore::VisibilityChangeClient::~VisibilityChangeClient):
* html/HTMLMediaElement.h:
Introduce a new VisibilityChangeClient interface and have both AudioContext
and HTMLMediaElement subclass it. Previously, the visibilityStateChanged()
function was on Element but this prevented AudioContext from registering
itself since AudioContext is not an Element.

LayoutTests:

Add layout test coverage.

* webaudio/silent-audio-interrupted-in-background-expected.txt: Added.
* webaudio/silent-audio-interrupted-in-background.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsplatformiosTestExpectations">trunk/LayoutTests/platform/ios/TestExpectations</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreModuleswebaudioAudioContextcpp">trunk/Source/WebCore/Modules/webaudio/AudioContext.cpp</a></li>
<li><a href="#trunkSourceWebCoreModuleswebaudioAudioContexth">trunk/Source/WebCore/Modules/webaudio/AudioContext.h</a></li>
<li><a href="#trunkSourceWebCoreWebCorexcodeprojprojectpbxproj">trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceWebCoredomDocumentcpp">trunk/Source/WebCore/dom/Document.cpp</a></li>
<li><a href="#trunkSourceWebCoredomDocumenth">trunk/Source/WebCore/dom/Document.h</a></li>
<li><a href="#trunkSourceWebCoredomElementh">trunk/Source/WebCore/dom/Element.h</a></li>
<li><a href="#trunkSourceWebCorehtmlHTMLMediaElementh">trunk/Source/WebCore/html/HTMLMediaElement.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestswebaudiosilentaudiointerruptedinbackgroundexpectedtxt">trunk/LayoutTests/webaudio/silent-audio-interrupted-in-background-expected.txt</a></li>
<li><a href="#trunkLayoutTestswebaudiosilentaudiointerruptedinbackgroundhtml">trunk/LayoutTests/webaudio/silent-audio-interrupted-in-background.html</a></li>
<li><a href="#trunkSourceWebCoredomVisibilityChangeClienth">trunk/Source/WebCore/dom/VisibilityChangeClient.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (214720 => 214721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2017-04-02 00:17:55 UTC (rev 214720)
+++ trunk/LayoutTests/ChangeLog        2017-04-02 00:55:20 UTC (rev 214721)
</span><span class="lines">@@ -1,3 +1,16 @@
</span><ins>+2017-04-01  Chris Dumez  &lt;cdumez@apple.com&gt;
+
+        We should pause silent WebAudio rendering in background tabs
+        https://bugs.webkit.org/show_bug.cgi?id=170299
+        &lt;rdar://problem/31289132&gt;
+
+        Reviewed by Eric Carlson.
+
+        Add layout test coverage.
+
+        * webaudio/silent-audio-interrupted-in-background-expected.txt: Added.
+        * webaudio/silent-audio-interrupted-in-background.html: Added.
+
</ins><span class="cx"> 2017-04-01  Alexey Proskuryakov  &lt;ap@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Rolling back http://trac.webkit.org/r214663 - memory corruption
</span></span></pre></div>
<a id="trunkLayoutTestsplatformiosTestExpectations"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/platform/ios/TestExpectations (214720 => 214721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/ios/TestExpectations        2017-04-02 00:17:55 UTC (rev 214720)
+++ trunk/LayoutTests/platform/ios/TestExpectations        2017-04-02 00:55:20 UTC (rev 214721)
</span><span class="lines">@@ -311,6 +311,7 @@
</span><span class="cx"> webkit.org/b/165799 svg/animations/animations-paused-page-non-visible.html [ Skip ]
</span><span class="cx"> webkit.org/b/165799 svg/animations/animations-paused-in-background-page-iframe.html [ Skip ]
</span><span class="cx"> webkit.org/b/165799 svg/animations/animations-paused-in-background-page.html [ Skip ]
</span><ins>+webkit.org/b/165799 webaudio/silent-audio-interrupted-in-background.html [ Skip ]
</ins><span class="cx"> 
</span><span class="cx"> # AutoFill button is not supported
</span><span class="cx"> fast/forms/auto-fill-button/mouse-down-input-mouse-release-auto-fill-button.html
</span></span></pre></div>
<a id="trunkLayoutTestswebaudiosilentaudiointerruptedinbackgroundexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/webaudio/silent-audio-interrupted-in-background-expected.txt (0 => 214721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/webaudio/silent-audio-interrupted-in-background-expected.txt                                (rev 0)
+++ trunk/LayoutTests/webaudio/silent-audio-interrupted-in-background-expected.txt        2017-04-02 00:55:20 UTC (rev 214721)
</span><span class="lines">@@ -0,0 +1,14 @@
</span><ins>+Tests that silent WebAudio rendering gets interrupted in hidden pages.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS context.state became 'running'
+* Setting page visibility to hidden
+PASS context.state became 'interrupted'
+* Setting page visibility to visible
+PASS context.state became 'running'
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestswebaudiosilentaudiointerruptedinbackgroundhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/webaudio/silent-audio-interrupted-in-background.html (0 => 214721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/webaudio/silent-audio-interrupted-in-background.html                                (rev 0)
+++ trunk/LayoutTests/webaudio/silent-audio-interrupted-in-background.html        2017-04-02 00:55:20 UTC (rev 214721)
</span><span class="lines">@@ -0,0 +1,50 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;body&gt;
+&lt;script src=&quot;../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;script&gt;
+description(&quot;Tests that silent WebAudio rendering gets interrupted in hidden pages.&quot;);
+jsTestIsAsync = true;
+
+document.onvisibilitychange = function() {
+    if (document.hidden) {
+        shouldBecomeEqual(&quot;context.state&quot;, &quot;'interrupted'&quot;, showPage);
+    } else {
+        shouldBecomeEqual(&quot;context.state&quot;, &quot;'running'&quot;, finishJSTest);
+    }
+}
+
+function showPage()
+{
+    debug(&quot;* Setting page visibility to visible&quot;);
+    if (window.testRunner)
+        testRunner.setPageVisibility(&quot;visible&quot;);
+}
+
+function hidePage()
+{
+    debug(&quot;* Setting page visibility to hidden&quot;);
+    if (window.testRunner)
+        testRunner.setPageVisibility(&quot;hidden&quot;);
+}
+
+onload = function() {
+    context = new (window.AudioContext || window.webkitAudioContext)();
+
+    audioElement = document.createElement(&quot;audio&quot;);
+    audioElement.loop = true;
+    audioElement.muted = true;
+    audioElement.src = &quot;../media/content/test.wav&quot;;
+    source = context.createMediaElementSource(audioElement);
+
+    var gainNode = context.createGain();
+    source.connect(gainNode);
+    gainNode.connect(context.destination);
+    gainNode.gain.value = 0; // Mute.
+
+    shouldBecomeEqual(&quot;context.state&quot;, &quot;'running'&quot;, hidePage);
+}
+&lt;/script&gt;
+&lt;script src=&quot;../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (214720 => 214721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2017-04-02 00:17:55 UTC (rev 214720)
+++ trunk/Source/WebCore/ChangeLog        2017-04-02 00:55:20 UTC (rev 214721)
</span><span class="lines">@@ -1,3 +1,44 @@
</span><ins>+2017-04-01  Chris Dumez  &lt;cdumez@apple.com&gt;
+
+        We should pause silent WebAudio rendering in background tabs
+        https://bugs.webkit.org/show_bug.cgi?id=170299
+        &lt;rdar://problem/31289132&gt;
+
+        Reviewed by Eric Carlson.
+
+        We should pause silent WebAudio rendering in background tabs since it uses CPU and is
+        not observable by the user. Such silent WebAudio rendering seems to be used by
+        doubleclick ads.
+
+        Test: webaudio/silent-audio-interrupted-in-background.html
+
+        * Modules/webaudio/AudioContext.cpp:
+        (WebCore::AudioContext::lazyInitialize):
+        (WebCore::AudioContext::uninitialize):
+        Have AudioContext register / unregister itself with the Document to get
+        visibility change notifications, similarly to what HTMLMediaElement was
+        already doing.
+
+        (WebCore::AudioContext::visibilityStateChanged):
+        Begin / End session interruption whenever the page visiblity changes.
+
+        * Modules/webaudio/AudioContext.h:
+        * WebCore.xcodeproj/project.pbxproj:
+
+        * dom/Document.cpp:
+        (WebCore::Document::registerForVisibilityStateChangedCallbacks):
+        (WebCore::Document::unregisterForVisibilityStateChangedCallbacks):
+        (WebCore::Document::visibilityStateChanged):
+        * dom/Document.h:
+        * dom/Element.h:
+        * dom/VisibilityChangeClient.h: Added.
+        (WebCore::VisibilityChangeClient::~VisibilityChangeClient):
+        * html/HTMLMediaElement.h:
+        Introduce a new VisibilityChangeClient interface and have both AudioContext
+        and HTMLMediaElement subclass it. Previously, the visibilityStateChanged()
+        function was on Element but this prevented AudioContext from registering
+        itself since AudioContext is not an Element.
+
</ins><span class="cx"> 2017-04-01  Dan Bernstein  &lt;mitz@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [Cocoa] A couple of UI strings use three periods instead of an ellipsis
</span></span></pre></div>
<a id="trunkSourceWebCoreModuleswebaudioAudioContextcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/webaudio/AudioContext.cpp (214720 => 214721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/webaudio/AudioContext.cpp        2017-04-02 00:17:55 UTC (rev 214720)
+++ trunk/Source/WebCore/Modules/webaudio/AudioContext.cpp        2017-04-02 00:55:20 UTC (rev 214721)
</span><span class="lines">@@ -54,6 +54,7 @@
</span><span class="cx"> #include &quot;HRTFDatabaseLoader.h&quot;
</span><span class="cx"> #include &quot;HRTFPanner.h&quot;
</span><span class="cx"> #include &quot;JSDOMPromise.h&quot;
</span><ins>+#include &quot;Logging.h&quot;
</ins><span class="cx"> #include &quot;NetworkingContext.h&quot;
</span><span class="cx"> #include &quot;OfflineAudioCompletionEvent.h&quot;
</span><span class="cx"> #include &quot;OfflineAudioDestinationNode.h&quot;
</span><span class="lines">@@ -104,6 +105,8 @@
</span><span class="cx"> const unsigned MaxPeriodicWaveLength = 4096;
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><ins>+
+#define RELEASE_LOG_IF_ALLOWED(fmt, ...) RELEASE_LOG_IF(document()-&gt;page() &amp;&amp; document()-&gt;page()-&gt;isAlwaysOnLoggingAllowed(), Media, &quot;%p - AudioContext::&quot; fmt, this, ##__VA_ARGS__)
</ins><span class="cx">     
</span><span class="cx"> bool AudioContext::isSampleRateRangeGood(float sampleRate)
</span><span class="cx"> {
</span><span class="lines">@@ -215,6 +218,7 @@
</span><span class="cx"> 
</span><span class="cx">         if (!isOfflineContext()) {
</span><span class="cx">             document()-&gt;addAudioProducer(this);
</span><ins>+            document()-&gt;registerForVisibilityStateChangedCallbacks(this);
</ins><span class="cx"> 
</span><span class="cx">             // This starts the audio thread. The destination node's provideInput() method will now be called repeatedly to render audio.
</span><span class="cx">             // Each time provideInput() is called, a portion of the audio stream is rendered. Let's call this time period a &quot;render quantum&quot;.
</span><span class="lines">@@ -259,6 +263,7 @@
</span><span class="cx"> 
</span><span class="cx">     if (!isOfflineContext()) {
</span><span class="cx">         document()-&gt;removeAudioProducer(this);
</span><ins>+        document()-&gt;unregisterForVisibilityStateChangedCallbacks(this);
</ins><span class="cx"> 
</span><span class="cx">         ASSERT(s_hardwareContextCount);
</span><span class="cx">         --s_hardwareContextCount;
</span><span class="lines">@@ -363,6 +368,25 @@
</span><span class="cx">     return emptyString();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void AudioContext::visibilityStateChanged()
+{
+    // Do not suspend if audio is audible.
+    if (mediaState() == MediaProducer::IsPlayingAudio)
+        return;
+
+    if (document()-&gt;hidden()) {
+        if (state() == State::Running) {
+            RELEASE_LOG_IF_ALLOWED(&quot;visibilityStateChanged() Suspending playback after going to the background&quot;);
+            m_mediaSession-&gt;beginInterruption(PlatformMediaSession::EnteringBackground);
+        }
+    } else {
+        if (state() == State::Interrupted) {
+            RELEASE_LOG_IF_ALLOWED(&quot;visibilityStateChanged() Resuming playback after entering foreground&quot;);
+            m_mediaSession-&gt;endInterruption(PlatformMediaSession::MayResumePlaying);
+        }
+    }
+}
+
</ins><span class="cx"> ExceptionOr&lt;Ref&lt;AudioBuffer&gt;&gt; AudioContext::createBuffer(unsigned numberOfChannels, size_t numberOfFrames, float sampleRate)
</span><span class="cx"> {
</span><span class="cx">     auto audioBuffer = AudioBuffer::create(numberOfChannels, numberOfFrames, sampleRate);
</span></span></pre></div>
<a id="trunkSourceWebCoreModuleswebaudioAudioContexth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/webaudio/AudioContext.h (214720 => 214721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/webaudio/AudioContext.h        2017-04-02 00:17:55 UTC (rev 214720)
+++ trunk/Source/WebCore/Modules/webaudio/AudioContext.h        2017-04-02 00:55:20 UTC (rev 214721)
</span><span class="lines">@@ -35,6 +35,7 @@
</span><span class="cx"> #include &quot;MediaCanStartListener.h&quot;
</span><span class="cx"> #include &quot;MediaProducer.h&quot;
</span><span class="cx"> #include &quot;PlatformMediaSession.h&quot;
</span><ins>+#include &quot;VisibilityChangeClient.h&quot;
</ins><span class="cx"> #include &lt;atomic&gt;
</span><span class="cx"> #include &lt;wtf/HashSet.h&gt;
</span><span class="cx"> #include &lt;wtf/MainThread.h&gt;
</span><span class="lines">@@ -75,7 +76,7 @@
</span><span class="cx"> // AudioContext is the cornerstone of the web audio API and all AudioNodes are created from it.
</span><span class="cx"> // For thread safety between the audio thread and the main thread, it has a rendering graph locking mechanism. 
</span><span class="cx"> 
</span><del>-class AudioContext : public ActiveDOMObject, public ThreadSafeRefCounted&lt;AudioContext&gt;, public EventTargetWithInlineData, public MediaCanStartListener, public MediaProducer, private PlatformMediaSessionClient {
</del><ins>+class AudioContext : public ActiveDOMObject, public ThreadSafeRefCounted&lt;AudioContext&gt;, public EventTargetWithInlineData, public MediaCanStartListener, public MediaProducer, private PlatformMediaSessionClient, private VisibilityChangeClient {
</ins><span class="cx"> public:
</span><span class="cx">     // Create an AudioContext for rendering to the audio hardware.
</span><span class="cx">     static RefPtr&lt;AudioContext&gt; create(Document&amp;);
</span><span class="lines">@@ -319,6 +320,8 @@
</span><span class="cx">     String sourceApplicationIdentifier() const override;
</span><span class="cx">     bool canProduceAudio() const final { return true; }
</span><span class="cx"> 
</span><ins>+    void visibilityStateChanged() final;
+
</ins><span class="cx">     // EventTarget
</span><span class="cx">     void refEventTarget() override { ref(); }
</span><span class="cx">     void derefEventTarget() override { deref(); }
</span></span></pre></div>
<a id="trunkSourceWebCoreWebCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (214720 => 214721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj        2017-04-02 00:17:55 UTC (rev 214720)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj        2017-04-02 00:55:20 UTC (rev 214721)
</span><span class="lines">@@ -3282,6 +3282,7 @@
</span><span class="cx">                 83120C711C56F3FB001CB112 /* HTMLDataElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 834B86A71C56E83A00F3F0E3 /* HTMLDataElement.h */; };
</span><span class="cx">                 832B843419D8E55100B26055 /* SVGAnimateElementBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 832B843319D8E55100B26055 /* SVGAnimateElementBase.h */; };
</span><span class="cx">                 832B843619D8E57400B26055 /* SVGAnimateElementBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 832B843519D8E57400B26055 /* SVGAnimateElementBase.cpp */; };
</span><ins>+                83407FC11E8D9C1700E048D3 /* VisibilityChangeClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 83407FC01E8D9C1200E048D3 /* VisibilityChangeClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
</ins><span class="cx">                 834476EE1DA5BC57002B6ED2 /* JSScrollToOptions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83E9B3001DA5A51E00FFE8F6 /* JSScrollToOptions.cpp */; };
</span><span class="cx">                 834476EF1DA5BC5E002B6ED2 /* JSScrollToOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 83E9B3011DA5A51E00FFE8F6 /* JSScrollToOptions.h */; };
</span><span class="cx">                 8348BFAB1B85729800912F36 /* ClassCollection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8348BFA91B85729500912F36 /* ClassCollection.cpp */; };
</span><span class="lines">@@ -11261,6 +11262,7 @@
</span><span class="cx">                 8329DCC21C7A6AE300730B33 /* HTMLHyperlinkElementUtils.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = HTMLHyperlinkElementUtils.idl; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 832B843319D8E55100B26055 /* SVGAnimateElementBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVGAnimateElementBase.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 832B843519D8E57400B26055 /* SVGAnimateElementBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SVGAnimateElementBase.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                83407FC01E8D9C1200E048D3 /* VisibilityChangeClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VisibilityChangeClient.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 8348BFA91B85729500912F36 /* ClassCollection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ClassCollection.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 8348BFAA1B85729500912F36 /* ClassCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ClassCollection.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 834B86A61C56E83A00F3F0E3 /* HTMLDataElement.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = HTMLDataElement.idl; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -25687,6 +25689,7 @@
</span><span class="cx">                                 BCDF317A11F8D683003C5BF8 /* UserTypingGestureIndicator.h */,
</span><span class="cx">                                 CEF418CC1179678C009D112C /* ViewportArguments.cpp */,
</span><span class="cx">                                 CEF418CD1179678C009D112C /* ViewportArguments.h */,
</span><ins>+                                83407FC01E8D9C1200E048D3 /* VisibilityChangeClient.h */,
</ins><span class="cx">                                 419BC2DC1685329900D64D6D /* VisitedLinkState.cpp */,
</span><span class="cx">                                 419BC2DD1685329900D64D6D /* VisitedLinkState.h */,
</span><span class="cx">                                 31C0FF1B0E4CEB6E007D6FE5 /* WebKitAnimationEvent.cpp */,
</span><span class="lines">@@ -29641,6 +29644,7 @@
</span><span class="cx">                                 26F9A83918A046AC00AEB88A /* ViewportConfiguration.h in Headers */,
</span><span class="cx">                                 3FFFF9AE159D9B060020BBD5 /* ViewportStyleResolver.h in Headers */,
</span><span class="cx">                                 93309E20099E64920056E581 /* VisiblePosition.h in Headers */,
</span><ins>+                                83407FC11E8D9C1700E048D3 /* VisibilityChangeClient.h in Headers */,
</ins><span class="cx">                                 A883DF280F3D045D00F19BF6 /* VisibleSelection.h in Headers */,
</span><span class="cx">                                 93309E1E099E64920056E581 /* VisibleUnits.h in Headers */,
</span><span class="cx">                                 419BC2DF1685329900D64D6D /* VisitedLinkState.h in Headers */,
</span></span></pre></div>
<a id="trunkSourceWebCoredomDocumentcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/Document.cpp (214720 => 214721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/Document.cpp        2017-04-02 00:17:55 UTC (rev 214720)
+++ trunk/Source/WebCore/dom/Document.cpp        2017-04-02 00:55:20 UTC (rev 214721)
</span><span class="lines">@@ -1530,21 +1530,21 @@
</span><span class="cx">     updateTitleFromTitleElement();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Document::registerForVisibilityStateChangedCallbacks(Element* element)
</del><ins>+void Document::registerForVisibilityStateChangedCallbacks(VisibilityChangeClient* client)
</ins><span class="cx"> {
</span><del>-    m_visibilityStateCallbackElements.add(element);
</del><ins>+    m_visibilityStateCallbackClients.add(client);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Document::unregisterForVisibilityStateChangedCallbacks(Element* element)
</del><ins>+void Document::unregisterForVisibilityStateChangedCallbacks(VisibilityChangeClient* client)
</ins><span class="cx"> {
</span><del>-    m_visibilityStateCallbackElements.remove(element);
</del><ins>+    m_visibilityStateCallbackClients.remove(client);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void Document::visibilityStateChanged()
</span><span class="cx"> {
</span><span class="cx">     dispatchEvent(Event::create(eventNames().visibilitychangeEvent, false, false));
</span><del>-    for (auto* element : m_visibilityStateCallbackElements)
-        element-&gt;visibilityStateChanged();
</del><ins>+    for (auto* client : m_visibilityStateCallbackClients)
+        client-&gt;visibilityStateChanged();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> auto Document::visibilityState() const -&gt; VisibilityState
</span></span></pre></div>
<a id="trunkSourceWebCoredomDocumenth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/Document.h (214720 => 214721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/Document.h        2017-04-02 00:17:55 UTC (rev 214720)
+++ trunk/Source/WebCore/dom/Document.h        2017-04-02 00:55:20 UTC (rev 214721)
</span><span class="lines">@@ -163,6 +163,7 @@
</span><span class="cx"> class Text;
</span><span class="cx"> class TextResourceDecoder;
</span><span class="cx"> class TreeWalker;
</span><ins>+class VisibilityChangeClient;
</ins><span class="cx"> class VisitedLinkState;
</span><span class="cx"> class XPathEvaluator;
</span><span class="cx"> class XPathExpression;
</span><span class="lines">@@ -1006,8 +1007,8 @@
</span><span class="cx">     void userInterfaceLayoutDirectionChanged();
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    void registerForVisibilityStateChangedCallbacks(Element*);
-    void unregisterForVisibilityStateChangedCallbacks(Element*);
</del><ins>+    void registerForVisibilityStateChangedCallbacks(VisibilityChangeClient*);
+    void unregisterForVisibilityStateChangedCallbacks(VisibilityChangeClient*);
</ins><span class="cx"> 
</span><span class="cx"> #if ENABLE(VIDEO)
</span><span class="cx">     void registerForAllowsMediaDocumentInlinePlaybackChangedCallbacks(HTMLMediaElement&amp;);
</span><span class="lines">@@ -1520,7 +1521,7 @@
</span><span class="cx">     HashSet&lt;HTMLMediaElement*&gt; m_userInterfaceLayoutDirectionChangedElements;
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    HashSet&lt;Element*&gt; m_visibilityStateCallbackElements;
</del><ins>+    HashSet&lt;VisibilityChangeClient*&gt; m_visibilityStateCallbackClients;
</ins><span class="cx"> #if ENABLE(VIDEO)
</span><span class="cx">     HashSet&lt;HTMLMediaElement*&gt; m_allowsMediaDocumentInlinePlaybackElements;
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkSourceWebCoredomElementh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/Element.h (214720 => 214721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/Element.h        2017-04-02 00:17:55 UTC (rev 214720)
+++ trunk/Source/WebCore/dom/Element.h        2017-04-02 00:55:20 UTC (rev 214721)
</span><span class="lines">@@ -400,9 +400,6 @@
</span><span class="cx">     virtual void didBecomeFullscreenElement() { }
</span><span class="cx">     virtual void willStopBeingFullscreenElement() { }
</span><span class="cx"> 
</span><del>-    // Use Document::registerForVisibilityStateChangedCallbacks() to subscribe to this.
-    virtual void visibilityStateChanged() { }
-
</del><span class="cx"> #if ENABLE(VIDEO_TRACK)
</span><span class="cx">     virtual void captionPreferencesChanged() { }
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkSourceWebCoredomVisibilityChangeClienth"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/dom/VisibilityChangeClient.h (0 => 214721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/VisibilityChangeClient.h                                (rev 0)
+++ trunk/Source/WebCore/dom/VisibilityChangeClient.h        2017-04-02 00:55:20 UTC (rev 214721)
</span><span class="lines">@@ -0,0 +1,37 @@
</span><ins>+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+namespace WebCore {
+
+class VisibilityChangeClient {
+public:
+    virtual ~VisibilityChangeClient() { }
+
+    virtual void visibilityStateChanged() = 0;
+};
+
+}
</ins></span></pre></div>
<a id="trunkSourceWebCorehtmlHTMLMediaElementh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/html/HTMLMediaElement.h (214720 => 214721)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/HTMLMediaElement.h        2017-04-02 00:17:55 UTC (rev 214720)
+++ trunk/Source/WebCore/html/HTMLMediaElement.h        2017-04-02 00:55:20 UTC (rev 214721)
</span><span class="lines">@@ -37,6 +37,7 @@
</span><span class="cx"> #include &quot;MediaElementSession.h&quot;
</span><span class="cx"> #include &quot;MediaProducer.h&quot;
</span><span class="cx"> #include &quot;UserInterfaceLayoutDirection.h&quot;
</span><ins>+#include &quot;VisibilityChangeClient.h&quot;
</ins><span class="cx"> 
</span><span class="cx"> #if ENABLE(VIDEO_TRACK)
</span><span class="cx"> #include &quot;AudioTrack.h&quot;
</span><span class="lines">@@ -111,6 +112,7 @@
</span><span class="cx">     , private MediaCanStartListener
</span><span class="cx">     , private MediaPlayerClient
</span><span class="cx">     , private MediaProducer
</span><ins>+    , private VisibilityChangeClient
</ins><span class="cx"> #if ENABLE(VIDEO_TRACK)
</span><span class="cx">     , private AudioTrackClient
</span><span class="cx">     , private TextTrackClient
</span></span></pre>
</div>
</div>

</body>
</html>