Media continues loading after rendered invisible (removed from DOM; scrolled off...
authorjer.noble@apple.com <jer.noble@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 15 May 2018 23:01:14 +0000 (23:01 +0000)
committerjer.noble@apple.com <jer.noble@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 15 May 2018 23:01:14 +0000 (23:01 +0000)
https://bugs.webkit.org/show_bug.cgi?id=185487

Reviewed by Eric Carlson.

Source/WebCore:

Test: media/video-buffering-allowed.html

When a media element is removed from the dom (e.g. through innerHTML=""), it doesn't
necessarily stop loading media data; it will continue to do so until its destructor is
called through garbage collection. Similarly, when a media element is rendered not-visible
by being scrolled off-screen or being made display:none, media loading continues. There
are legitimate use cases for out-of-DOM media loading, so only temporarily block loading
when the element transitions out of the document. Similarly, only block loading for non-visible
media elements when returning from the "page is hidden" state, and only until the media
element is asked to play or is otherwise made visible.

Note: this refactors a lot of code out of PlatformMediaSession and into MediaElementSession,
since this code is specific to "media elements".

* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::HTMLMediaElement):
(WebCore::HTMLMediaElement::insertedIntoAncestor):
(WebCore::HTMLMediaElement::removedFromAncestor):
(WebCore::HTMLMediaElement::playInternal):
(WebCore::HTMLMediaElement::stopWithoutDestroyingMediaPlayer):
(WebCore::HTMLMediaElement::resume):
(WebCore::HTMLMediaElement::visibilityStateChanged):
(WebCore::HTMLMediaElement::createMediaPlayer):
(WebCore::HTMLMediaElement::setShouldBufferData):
(WebCore::HTMLMediaElement::purgeBufferedDataIfPossible):
(WebCore::HTMLMediaElement::isVisibleInViewportChanged):
(WebCore::HTMLMediaElement::fullscreenModeChanged):
(WebCore::HTMLMediaElement::setInActiveDocument):
* html/HTMLMediaElement.h:
(WebCore::HTMLMediaElement::shouldBufferData const):
(WebCore::HTMLMediaElement::elementIsHidden const):
* html/MediaElementSession.cpp:
(WebCore::MediaElementSession::MediaElementSession):
(WebCore::MediaElementSession::clientWillBeginAutoplaying):
(WebCore::MediaElementSession::clientWillBeginPlayback):
(WebCore::MediaElementSession::clientWillPausePlayback):
(WebCore::MediaElementSession::visibilityChanged):
(WebCore::MediaElementSession::isVisibleInViewportChanged):
(WebCore::MediaElementSession::inActiveDocumentChanged):
(WebCore::MediaElementSession::scheduleClientDataBufferingCheck):
(WebCore::MediaElementSession::clientDataBufferingTimerFired):
(WebCore::MediaElementSession::updateClientDataBuffering):
(WebCore::MediaElementSession::dataBufferingPermitted const):
(WebCore::MediaElementSession::wantsToObserveViewportVisibilityForAutoplay const):
* html/MediaElementSession.h:
* platform/audio/PlatformMediaSession.cpp:
(WebCore::PlatformMediaSession::PlatformMediaSession):
(WebCore::PlatformMediaSession::clientWillBeginAutoplaying):
(WebCore::PlatformMediaSession::clientWillBeginPlayback):
(WebCore::PlatformMediaSession::clientWillPausePlayback):
(): Deleted.
(WebCore::PlatformMediaSession::visibilityChanged): Deleted.
(WebCore::PlatformMediaSession::scheduleClientDataBufferingCheck): Deleted.
(WebCore::PlatformMediaSession::clientDataBufferingTimerFired): Deleted.
(WebCore::PlatformMediaSession::updateClientDataBuffering): Deleted.
(WebCore::PlatformMediaSession::isHidden const): Deleted.
* platform/audio/PlatformMediaSession.h:
(WebCore::PlatformMediaSessionClient::setShouldBufferData): Deleted.
(WebCore::PlatformMediaSessionClient::elementIsHidden const): Deleted.
* platform/audio/PlatformMediaSessionManager.cpp:
(WebCore::PlatformMediaSessionManager::sessionCanLoadMedia const): Deleted.
* platform/audio/PlatformMediaSessionManager.h:
* platform/audio/ios/MediaSessionManagerIOS.h:
* platform/audio/ios/MediaSessionManagerIOS.mm:
(WebCore::MediaSessionManageriOS::sessionCanLoadMedia const): Deleted.
* rendering/RenderVideo.cpp:
(WebCore::RenderVideo::willBeDestroyed):
* testing/Internals.cpp:
(WebCore::Internals::elementShouldBufferData):
* testing/Internals.h:
* testing/Internals.idl:

LayoutTests:

* media/video-buffering-allowed-expected.txt: Added.
* media/video-buffering-allowed.html: Added.
* media/video-test.js:
(compare):
(testExpected):
(sleepFor):
(testArraysEqual): Deleted.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@231817 268f45cc-cd09-0410-ab3c-d52691b4dbfc

20 files changed:
LayoutTests/ChangeLog
LayoutTests/media/media-source/only-bcp47-language-tags-accepted-as-valid-expected.txt
LayoutTests/media/video-buffering-allowed-expected.txt [new file with mode: 0644]
LayoutTests/media/video-buffering-allowed.html [new file with mode: 0644]
LayoutTests/media/video-test.js
Source/WebCore/ChangeLog
Source/WebCore/html/HTMLMediaElement.cpp
Source/WebCore/html/HTMLMediaElement.h
Source/WebCore/html/MediaElementSession.cpp
Source/WebCore/html/MediaElementSession.h
Source/WebCore/platform/audio/PlatformMediaSession.cpp
Source/WebCore/platform/audio/PlatformMediaSession.h
Source/WebCore/platform/audio/PlatformMediaSessionManager.cpp
Source/WebCore/platform/audio/PlatformMediaSessionManager.h
Source/WebCore/platform/audio/ios/MediaSessionManagerIOS.h
Source/WebCore/platform/audio/ios/MediaSessionManagerIOS.mm
Source/WebCore/rendering/RenderVideo.cpp
Source/WebCore/testing/Internals.cpp
Source/WebCore/testing/Internals.h
Source/WebCore/testing/Internals.idl

index 52440ef..20fe42c 100644 (file)
@@ -1,3 +1,18 @@
+2018-05-15  Jer Noble  <jer.noble@apple.com>
+
+        Media continues loading after rendered invisible (removed from DOM; scrolled off screen)
+        https://bugs.webkit.org/show_bug.cgi?id=185487
+
+        Reviewed by Eric Carlson.
+
+        * media/video-buffering-allowed-expected.txt: Added.
+        * media/video-buffering-allowed.html: Added.
+        * media/video-test.js:
+        (compare):
+        (testExpected):
+        (sleepFor):
+        (testArraysEqual): Deleted.
+
 2018-05-15  Charles Vazac  <cvazac@gmail.com>
 
         Add the PerformanceServerTiming Interface which makes Server-Timing header timing values available to JavaScript running in the browser.
index a11aa4a..54a6e48 100644 (file)
@@ -1,48 +1,48 @@
-CONSOLE MESSAGE: line 176: The language 'a' is not a valid BCP 47 language tag.
+CONSOLE MESSAGE: line 221: The language 'a' is not a valid BCP 47 language tag.
 CONSOLE MESSAGE: line 106: The language 'a' is not a valid BCP 47 language tag.
-CONSOLE MESSAGE: line 176: The language 'a' is not a valid BCP 47 language tag.
-CONSOLE MESSAGE: line 176: The language '1' is not a valid BCP 47 language tag.
+CONSOLE MESSAGE: line 221: The language 'a' is not a valid BCP 47 language tag.
+CONSOLE MESSAGE: line 221: The language '1' is not a valid BCP 47 language tag.
 CONSOLE MESSAGE: line 106: The language '1' is not a valid BCP 47 language tag.
-CONSOLE MESSAGE: line 176: The language '1' is not a valid BCP 47 language tag.
-CONSOLE MESSAGE: line 176: The language 'ab-abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij' is not a valid BCP 47 language tag.
+CONSOLE MESSAGE: line 221: The language '1' is not a valid BCP 47 language tag.
+CONSOLE MESSAGE: line 221: The language 'ab-abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij' is not a valid BCP 47 language tag.
 CONSOLE MESSAGE: line 106: The language 'ab-abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij' is not a valid BCP 47 language tag.
-CONSOLE MESSAGE: line 176: The language 'ab-abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij' is not a valid BCP 47 language tag.
-CONSOLE MESSAGE: line 176: The language '1a' is not a valid BCP 47 language tag.
+CONSOLE MESSAGE: line 221: The language 'ab-abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij' is not a valid BCP 47 language tag.
+CONSOLE MESSAGE: line 221: The language '1a' is not a valid BCP 47 language tag.
 CONSOLE MESSAGE: line 106: The language '1a' is not a valid BCP 47 language tag.
-CONSOLE MESSAGE: line 176: The language '1a' is not a valid BCP 47 language tag.
-CONSOLE MESSAGE: line 176: The language '-a' is not a valid BCP 47 language tag.
+CONSOLE MESSAGE: line 221: The language '1a' is not a valid BCP 47 language tag.
+CONSOLE MESSAGE: line 221: The language '-a' is not a valid BCP 47 language tag.
 CONSOLE MESSAGE: line 106: The language '-a' is not a valid BCP 47 language tag.
-CONSOLE MESSAGE: line 176: The language '-a' is not a valid BCP 47 language tag.
-CONSOLE MESSAGE: line 176: The language 'a-' is not a valid BCP 47 language tag.
+CONSOLE MESSAGE: line 221: The language '-a' is not a valid BCP 47 language tag.
+CONSOLE MESSAGE: line 221: The language 'a-' is not a valid BCP 47 language tag.
 CONSOLE MESSAGE: line 106: The language 'a-' is not a valid BCP 47 language tag.
-CONSOLE MESSAGE: line 176: The language 'a-' is not a valid BCP 47 language tag.
-CONSOLE MESSAGE: line 176: The language 'a1' is not a valid BCP 47 language tag.
+CONSOLE MESSAGE: line 221: The language 'a-' is not a valid BCP 47 language tag.
+CONSOLE MESSAGE: line 221: The language 'a1' is not a valid BCP 47 language tag.
 CONSOLE MESSAGE: line 106: The language 'a1' is not a valid BCP 47 language tag.
-CONSOLE MESSAGE: line 176: The language 'a1' is not a valid BCP 47 language tag.
-CONSOLE MESSAGE: line 176: The language 'aa1' is not a valid BCP 47 language tag.
+CONSOLE MESSAGE: line 221: The language 'a1' is not a valid BCP 47 language tag.
+CONSOLE MESSAGE: line 221: The language 'aa1' is not a valid BCP 47 language tag.
 CONSOLE MESSAGE: line 106: The language 'aa1' is not a valid BCP 47 language tag.
-CONSOLE MESSAGE: line 176: The language 'aa1' is not a valid BCP 47 language tag.
-CONSOLE MESSAGE: line 176: The language 'aaaa' is not a valid BCP 47 language tag.
+CONSOLE MESSAGE: line 221: The language 'aa1' is not a valid BCP 47 language tag.
+CONSOLE MESSAGE: line 221: The language 'aaaa' is not a valid BCP 47 language tag.
 CONSOLE MESSAGE: line 106: The language 'aaaa' is not a valid BCP 47 language tag.
-CONSOLE MESSAGE: line 176: The language 'aaaa' is not a valid BCP 47 language tag.
-CONSOLE MESSAGE: line 176: The language 'aaa1' is not a valid BCP 47 language tag.
+CONSOLE MESSAGE: line 221: The language 'aaaa' is not a valid BCP 47 language tag.
+CONSOLE MESSAGE: line 221: The language 'aaa1' is not a valid BCP 47 language tag.
 CONSOLE MESSAGE: line 106: The language 'aaa1' is not a valid BCP 47 language tag.
-CONSOLE MESSAGE: line 176: The language 'aaa1' is not a valid BCP 47 language tag.
-CONSOLE MESSAGE: line 176: The language 'inv-alid-char space' is not a valid BCP 47 language tag.
+CONSOLE MESSAGE: line 221: The language 'aaa1' is not a valid BCP 47 language tag.
+CONSOLE MESSAGE: line 221: The language 'inv-alid-char space' is not a valid BCP 47 language tag.
 CONSOLE MESSAGE: line 106: The language 'inv-alid-char space' is not a valid BCP 47 language tag.
-CONSOLE MESSAGE: line 176: The language 'inv-alid-char space' is not a valid BCP 47 language tag.
-CONSOLE MESSAGE: line 176: The language 'inv-alid-char–longDash' is not a valid BCP 47 language tag.
+CONSOLE MESSAGE: line 221: The language 'inv-alid-char space' is not a valid BCP 47 language tag.
+CONSOLE MESSAGE: line 221: The language 'inv-alid-char–longDash' is not a valid BCP 47 language tag.
 CONSOLE MESSAGE: line 106: The language 'inv-alid-char–longDash' is not a valid BCP 47 language tag.
-CONSOLE MESSAGE: line 176: The language 'inv-alid-char–longDash' is not a valid BCP 47 language tag.
-CONSOLE MESSAGE: line 176: The language 'inv-alid-char-PÃ¥lska' is not a valid BCP 47 language tag.
+CONSOLE MESSAGE: line 221: The language 'inv-alid-char–longDash' is not a valid BCP 47 language tag.
+CONSOLE MESSAGE: line 221: The language 'inv-alid-char-PÃ¥lska' is not a valid BCP 47 language tag.
 CONSOLE MESSAGE: line 106: The language 'inv-alid-char-PÃ¥lska' is not a valid BCP 47 language tag.
-CONSOLE MESSAGE: line 176: The language 'inv-alid-char-PÃ¥lska' is not a valid BCP 47 language tag.
-CONSOLE MESSAGE: line 176: The language 'inv-alid-char-*' is not a valid BCP 47 language tag.
+CONSOLE MESSAGE: line 221: The language 'inv-alid-char-PÃ¥lska' is not a valid BCP 47 language tag.
+CONSOLE MESSAGE: line 221: The language 'inv-alid-char-*' is not a valid BCP 47 language tag.
 CONSOLE MESSAGE: line 106: The language 'inv-alid-char-*' is not a valid BCP 47 language tag.
-CONSOLE MESSAGE: line 176: The language 'inv-alid-char-*' is not a valid BCP 47 language tag.
-CONSOLE MESSAGE: line 176: The language 'inv-alid-char-' is not a valid BCP 47 language tag.
+CONSOLE MESSAGE: line 221: The language 'inv-alid-char-*' is not a valid BCP 47 language tag.
+CONSOLE MESSAGE: line 221: The language 'inv-alid-char-' is not a valid BCP 47 language tag.
 CONSOLE MESSAGE: line 106: The language 'inv-alid-char-' is not a valid BCP 47 language tag.
-CONSOLE MESSAGE: line 176: The language 'inv-alid-char-' is not a valid BCP 47 language tag.
+CONSOLE MESSAGE: line 221: The language 'inv-alid-char-' is not a valid BCP 47 language tag.
 Test that only BCP47 language tags are accepted as valid but still reflected.
 
 
diff --git a/LayoutTests/media/video-buffering-allowed-expected.txt b/LayoutTests/media/video-buffering-allowed-expected.txt
new file mode 100644 (file)
index 0000000..1da49de
--- /dev/null
@@ -0,0 +1,32 @@
+
+RUN(video.src = findMediaFile("video", "content/test"))
+EVENT(canplaythrough)
+EXPECTED (internals.elementShouldBufferData(video) == 'true') OK
+* Remove the video element from the document.
+RUN(video.parentNode.removeChild(video))
+EXPECTED (internals.elementShouldBufferData(video) == 'false') OK
+* Play the video.
+RUN(video.play())
+EVENT(playing)
+EXPECTED (internals.elementShouldBufferData(video) == 'true') OK
+* Pause the video.
+RUN(video.pause())
+EVENT(pause)
+EXPECTED (internals.elementShouldBufferData(video) == 'true') OK
+* Re-insert the video element into the document.
+RUN(document.body.insertBefore(video, document.body.firstChild))
+EXPECTED (internals.elementShouldBufferData(video) == 'true') OK
+* display:none the video element.
+RUN(video.style.display = "none")
+EXPECTED (internals.elementShouldBufferData(video) == 'true') OK
+* Simulate the view becoming invisible.
+RUN(internals.setPageVisibility(false))
+EXPECTED (internals.elementShouldBufferData(video) == 'false') OK
+* Simulate the view becoming visible.
+RUN(internals.setPageVisibility(true))
+EXPECTED (internals.elementShouldBufferData(video) == 'false') OK
+* Remove display:none from the video element.
+RUN(video.style.removeProperty("display"))
+EXPECTED (internals.elementShouldBufferData(video) == 'true') OK
+END OF TEST
+
diff --git a/LayoutTests/media/video-buffering-allowed.html b/LayoutTests/media/video-buffering-allowed.html
new file mode 100644 (file)
index 0000000..6fbbe15
--- /dev/null
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>video-buffering-allowed</title>
+    <script src=media-file.js></script>
+    <script src=video-test.js></script>
+    <script>
+        async function runTest() {
+            findMediaElement();
+            failTestIn(1000);
+
+            run('video.src = findMediaFile("video", "content/test")');
+            await waitFor(video, 'canplaythrough');
+            testExpected('internals.elementShouldBufferData(video)', true);
+
+            consoleWrite('* Remove the video element from the document.');
+            run('video.parentNode.removeChild(video)');
+            await testExpectedEventually('internals.elementShouldBufferData(video)', false);
+
+            consoleWrite('* Play the video.');
+            run ('video.play()');
+            await waitFor(video, 'playing');
+            testExpected('internals.elementShouldBufferData(video)', true);
+
+            consoleWrite('* Pause the video.');
+            run('video.pause()');
+            await waitFor(video, 'pause');
+            testExpected('internals.elementShouldBufferData(video)', true);
+
+            consoleWrite('* Re-insert the video element into the document.');
+            run('document.body.insertBefore(video, document.body.firstChild)');
+            await testExpectedEventually('internals.elementShouldBufferData(video)', true);
+
+            consoleWrite('* display:none the video element.');
+            run('video.style.display = "none"');
+            await testExpectedEventually('internals.elementShouldBufferData(video)', true);
+
+            consoleWrite('* Simulate the view becoming invisible.');
+            run('internals.setPageVisibility(false)');
+            await testExpectedEventually('internals.elementShouldBufferData(video)', false);
+
+            consoleWrite('* Simulate the view becoming visible.');
+            run('internals.setPageVisibility(true)');
+            await testExpectedEventually('internals.elementShouldBufferData(video)', false);
+
+            consoleWrite('* Remove display:none from the video element.');
+            run('video.style.removeProperty("display")');
+            await testExpectedEventually('internals.elementShouldBufferData(video)', true);
+
+            endTest();
+        }
+        window.addEventListener('load', runTest);
+    </script>
+</head>
+<body>
+    <video controls></video>
+</body>
+</html>
index d4b463c..6eb110f 100644 (file)
@@ -62,17 +62,9 @@ function test(testFuncString, endit)
         endTest();
 }
 
-function testExpected(testFuncString, expected, comparison)
+function compare(testFuncString, expected, comparison)
 {
-    try {
-        var observed = eval(testFuncString);
-    } catch (ex) {
-        consoleWrite(ex);
-        return;
-    }
-
-    if (comparison === undefined)
-        comparison = '==';
+    var observed = eval(testFuncString);
 
     var success = false;
     switch (comparison)
@@ -87,7 +79,51 @@ function testExpected(testFuncString, expected, comparison)
         case 'instanceof': success = observed instanceof expected; break;
     }
 
-    reportExpected(success, testFuncString, comparison, expected, observed)
+    return {success:success, observed:observed};
+}
+
+function testExpected(testFuncString, expected, comparison)
+{
+    if (comparison === undefined)
+        comparison = '==';
+
+    try {
+        let {success, observed} = compare(testFuncString, expected, comparison);
+        reportExpected(success, testFuncString, comparison, expected, observed)
+    } catch (ex) {
+        consoleWrite(ex);
+    }
+}
+
+function sleepFor(duration) {
+    return new Promise(resolve => {
+        setTimeout(resolve, duration);
+    });
+}
+
+function testExpectedEventually(testFuncString, expected, comparison)
+{
+    return new Promise(async resolve => {
+        var success;
+        var observed;
+        if (comparison === undefined)
+            comparison = '==';
+        while (true) {
+            try {
+                let {success, observed} = compare(testFuncString, expected, comparison);
+                if (success) {
+                    reportExpected(success, testFuncString, comparison, expected, observed);
+                    resolve();
+                    return;
+                }
+                await sleepFor(1);
+            } catch (ex) {
+                consoleWrite(ex);
+                resolve();
+                return;
+            }
+        }
+    });
 }
 
 function testArraysEqual(testFuncString, expected)
@@ -150,6 +186,15 @@ function run(testFuncString)
     }
 }
 
+function waitFor(element, event) {
+    return new Promise(resolve => {
+        element.addEventListener(event, event => {
+            consoleWrite(`EVENT(${event.type})`);
+            resolve(event);
+        }, { once: true });
+    });
+}
+
 function waitForEventOnce(eventName, func, endit)
 {
     waitForEvent(eventName, func, endit, true)
index ecfcf72..ab19391 100644 (file)
@@ -1,3 +1,82 @@
+2018-05-15  Jer Noble  <jer.noble@apple.com>
+
+        Media continues loading after rendered invisible (removed from DOM; scrolled off screen)
+        https://bugs.webkit.org/show_bug.cgi?id=185487
+
+        Reviewed by Eric Carlson.
+
+        Test: media/video-buffering-allowed.html
+
+        When a media element is removed from the dom (e.g. through innerHTML=""), it doesn't
+        necessarily stop loading media data; it will continue to do so until its destructor is
+        called through garbage collection. Similarly, when a media element is rendered not-visible
+        by being scrolled off-screen or being made display:none, media loading continues. There
+        are legitimate use cases for out-of-DOM media loading, so only temporarily block loading
+        when the element transitions out of the document. Similarly, only block loading for non-visible
+        media elements when returning from the "page is hidden" state, and only until the media
+        element is asked to play or is otherwise made visible.
+
+        Note: this refactors a lot of code out of PlatformMediaSession and into MediaElementSession,
+        since this code is specific to "media elements".
+
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::HTMLMediaElement):
+        (WebCore::HTMLMediaElement::insertedIntoAncestor):
+        (WebCore::HTMLMediaElement::removedFromAncestor):
+        (WebCore::HTMLMediaElement::playInternal):
+        (WebCore::HTMLMediaElement::stopWithoutDestroyingMediaPlayer):
+        (WebCore::HTMLMediaElement::resume):
+        (WebCore::HTMLMediaElement::visibilityStateChanged):
+        (WebCore::HTMLMediaElement::createMediaPlayer):
+        (WebCore::HTMLMediaElement::setShouldBufferData):
+        (WebCore::HTMLMediaElement::purgeBufferedDataIfPossible):
+        (WebCore::HTMLMediaElement::isVisibleInViewportChanged):
+        (WebCore::HTMLMediaElement::fullscreenModeChanged):
+        (WebCore::HTMLMediaElement::setInActiveDocument):
+        * html/HTMLMediaElement.h:
+        (WebCore::HTMLMediaElement::shouldBufferData const):
+        (WebCore::HTMLMediaElement::elementIsHidden const):
+        * html/MediaElementSession.cpp:
+        (WebCore::MediaElementSession::MediaElementSession):
+        (WebCore::MediaElementSession::clientWillBeginAutoplaying):
+        (WebCore::MediaElementSession::clientWillBeginPlayback):
+        (WebCore::MediaElementSession::clientWillPausePlayback):
+        (WebCore::MediaElementSession::visibilityChanged):
+        (WebCore::MediaElementSession::isVisibleInViewportChanged):
+        (WebCore::MediaElementSession::inActiveDocumentChanged):
+        (WebCore::MediaElementSession::scheduleClientDataBufferingCheck):
+        (WebCore::MediaElementSession::clientDataBufferingTimerFired):
+        (WebCore::MediaElementSession::updateClientDataBuffering):
+        (WebCore::MediaElementSession::dataBufferingPermitted const):
+        (WebCore::MediaElementSession::wantsToObserveViewportVisibilityForAutoplay const):
+        * html/MediaElementSession.h:
+        * platform/audio/PlatformMediaSession.cpp:
+        (WebCore::PlatformMediaSession::PlatformMediaSession):
+        (WebCore::PlatformMediaSession::clientWillBeginAutoplaying):
+        (WebCore::PlatformMediaSession::clientWillBeginPlayback):
+        (WebCore::PlatformMediaSession::clientWillPausePlayback):
+        (): Deleted.
+        (WebCore::PlatformMediaSession::visibilityChanged): Deleted.
+        (WebCore::PlatformMediaSession::scheduleClientDataBufferingCheck): Deleted.
+        (WebCore::PlatformMediaSession::clientDataBufferingTimerFired): Deleted.
+        (WebCore::PlatformMediaSession::updateClientDataBuffering): Deleted.
+        (WebCore::PlatformMediaSession::isHidden const): Deleted.
+        * platform/audio/PlatformMediaSession.h:
+        (WebCore::PlatformMediaSessionClient::setShouldBufferData): Deleted.
+        (WebCore::PlatformMediaSessionClient::elementIsHidden const): Deleted.
+        * platform/audio/PlatformMediaSessionManager.cpp:
+        (WebCore::PlatformMediaSessionManager::sessionCanLoadMedia const): Deleted.
+        * platform/audio/PlatformMediaSessionManager.h:
+        * platform/audio/ios/MediaSessionManagerIOS.h:
+        * platform/audio/ios/MediaSessionManagerIOS.mm:
+        (WebCore::MediaSessionManageriOS::sessionCanLoadMedia const): Deleted.
+        * rendering/RenderVideo.cpp:
+        (WebCore::RenderVideo::willBeDestroyed):
+        * testing/Internals.cpp:
+        (WebCore::Internals::elementShouldBufferData):
+        * testing/Internals.h:
+        * testing/Internals.idl:
+
 2018-05-15  Charles Vazac  <cvazac@gmail.com>
 
         Add the PerformanceServerTiming Interface which makes Server-Timing header timing values available to JavaScript running in the browser.
index 96cf8b9..7b9fa08 100644 (file)
@@ -477,6 +477,7 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document& docum
     , m_completelyLoaded(false)
     , m_havePreparedToPlay(false)
     , m_parsingInProgress(createdByParser)
+    , m_shouldBufferData(true)
     , m_elementIsHidden(document.hidden())
     , m_creatingControls(false)
     , m_receivedLayoutSizeChanged(false)
@@ -926,7 +927,7 @@ Node::InsertedIntoAncestorResult HTMLMediaElement::insertedIntoAncestor(Insertio
 
     HTMLElement::insertedIntoAncestor(insertionType, parentOfInsertedTree);
     if (insertionType.connectedToDocument)
-        m_inActiveDocument = true;
+        setInActiveDocument(true);
 
     return InsertedIntoAncestorResult::NeedsPostInsertionCallback;
 }
@@ -978,7 +979,7 @@ void HTMLMediaElement::removedFromAncestor(RemovalType removalType, ContainerNod
 {
     INFO_LOG(LOGIDENTIFIER);
 
-    m_inActiveDocument = false;
+    setInActiveDocument(false);
     if (removalType.disconnectedFromDocument) {
         // Pause asynchronously to let the operation that removed us finish, in case we get inserted back into a document.
         m_pauseAfterDetachedTaskQueue.enqueueTask(std::bind(&HTMLMediaElement::pauseAfterDetachedTask, this));
@@ -3467,7 +3468,7 @@ void HTMLMediaElement::playInternal()
         ALWAYS_LOG(LOGIDENTIFIER, "  returning because of interruption");
         return;
     }
-
+    
     // 4.8.10.9. Playing the media resource
     if (!m_player || m_networkState == NETWORK_EMPTY)
         selectMediaResource();
@@ -5520,7 +5521,7 @@ void HTMLMediaElement::stopWithoutDestroyingMediaPlayer()
     setPreparedToReturnVideoLayerToInline(true);
 
     updatePlaybackControlsManager();
-    m_inActiveDocument = false;
+    setInActiveDocument(false);
 
     // Stop the playback without generating events
     setPlaying(false);
@@ -5600,7 +5601,7 @@ void HTMLMediaElement::resume()
 {
     INFO_LOG(LOGIDENTIFIER);
 
-    m_inActiveDocument = true;
+    setInActiveDocument(true);
 
     m_asyncEventQueue.resume();
 
@@ -5638,8 +5639,13 @@ void HTMLMediaElement::mediaVolumeDidChange()
 
 void HTMLMediaElement::visibilityStateChanged()
 {
-    m_elementIsHidden = document().hidden() && m_videoFullscreenMode != VideoFullscreenModePictureInPicture;
+    bool elementIsHidden = document().hidden() && m_videoFullscreenMode != VideoFullscreenModePictureInPicture;
+    if (elementIsHidden == m_elementIsHidden)
+        return;
+
+    m_elementIsHidden = elementIsHidden;
     INFO_LOG(LOGIDENTIFIER, "visible = ", !m_elementIsHidden);
+
     updateSleepDisabling();
     m_mediaSession->visibilityChanged();
     if (m_player)
@@ -6499,6 +6505,7 @@ void HTMLMediaElement::createMediaPlayer()
     forgetResourceSpecificTracks();
 #endif
     m_player = MediaPlayer::create(*this);
+    m_player->setShouldBufferData(m_shouldBufferData);
     scheduleUpdatePlaybackControlsManager();
 
 #if ENABLE(WEB_AUDIO)
@@ -7660,6 +7667,10 @@ bool HTMLMediaElement::doesHaveAttribute(const AtomicString& attribute, AtomicSt
 
 void HTMLMediaElement::setShouldBufferData(bool shouldBuffer)
 {
+    if (shouldBuffer == m_shouldBufferData)
+        return;
+
+    m_shouldBufferData = shouldBuffer;
     if (m_player)
         m_player->setShouldBufferData(shouldBuffer);
 }
@@ -7667,7 +7678,7 @@ void HTMLMediaElement::setShouldBufferData(bool shouldBuffer)
 void HTMLMediaElement::purgeBufferedDataIfPossible()
 {
 #if PLATFORM(IOS)
-    if (!MemoryPressureHandler::singleton().isUnderMemoryPressure() && PlatformMediaSessionManager::sharedManager().sessionCanLoadMedia(*m_mediaSession))
+    if (!MemoryPressureHandler::singleton().isUnderMemoryPressure() && m_mediaSession->dataBufferingPermitted())
         return;
 
     if (m_isPlayingToWirelessTarget) {
@@ -7775,6 +7786,7 @@ bool HTMLMediaElement::isVideoTooSmallForInlinePlayback()
 void HTMLMediaElement::isVisibleInViewportChanged()
 {
     m_visibilityChangeTaskQueue.enqueueTask([this] {
+        m_mediaSession->isVisibleInViewportChanged();
         updateShouldAutoplay();
         scheduleUpdatePlaybackControlsManager();
     });
@@ -7874,7 +7886,6 @@ void HTMLMediaElement::fullscreenModeChanged(VideoFullscreenMode mode)
 
     m_videoFullscreenMode = mode;
     visibilityStateChanged();
-    m_mediaSession->scheduleClientDataBufferingCheck();
     scheduleUpdatePlaybackControlsManager();
 }
 
@@ -7907,6 +7918,15 @@ void HTMLMediaElement::applicationDidBecomeActive()
         m_player->applicationDidBecomeActive();
 }
 
+void HTMLMediaElement::setInActiveDocument(bool inActiveDocument)
+{
+    if (inActiveDocument == m_inActiveDocument)
+        return;
+
+    m_inActiveDocument = inActiveDocument;
+    m_mediaSession->inActiveDocumentChanged();
+}
+
 }
 
 #endif
index 79f1af0..c8b94b5 100644 (file)
@@ -265,7 +265,8 @@ public:
 
     WEBCORE_EXPORT void play() override;
     WEBCORE_EXPORT void pause() override;
-    void setShouldBufferData(bool) override;
+    void setShouldBufferData(bool);
+    WEBCORE_EXPORT bool shouldBufferData() const { return m_shouldBufferData; }
     WEBCORE_EXPORT void fastSeek(double);
     double minFastReverseRate() const;
     double maxFastForwardRate() const;
@@ -277,7 +278,7 @@ public:
     WEBCORE_EXPORT bool webkitClosedCaptionsVisible() const;
     WEBCORE_EXPORT void setWebkitClosedCaptionsVisible(bool);
 
-    bool elementIsHidden() const override { return m_elementIsHidden; }
+    bool elementIsHidden() const { return m_elementIsHidden; }
 
 #if ENABLE(MEDIA_STATISTICS)
 // Statistics
@@ -912,6 +913,8 @@ private:
     void applicationWillResignActive() final;
     void applicationDidBecomeActive() final;
 
+    void setInActiveDocument(bool);
+
 #if !RELEASE_LOG_DISABLED
     const char* logClassName() const final { return "HTMLMediaElement"; }
 
@@ -1064,7 +1067,9 @@ private:
     bool m_completelyLoaded : 1;
     bool m_havePreparedToPlay : 1;
     bool m_parsingInProgress : 1;
+    bool m_shouldBufferData : 1;
     bool m_elementIsHidden : 1;
+    bool m_elementWasRemovedFromDOM : 1;
     bool m_creatingControls : 1;
     bool m_receivedLayoutSizeChanged : 1;
     bool m_hasEverNotifiedAboutPlaying : 1;
index 34b3e86..c2bd79a 100644 (file)
@@ -56,6 +56,7 @@
 
 namespace WebCore {
 
+static const Seconds clientDataBufferingTimerThrottleDelay { 100_ms };
 static const Seconds elementMainContentCheckInterval { 250_ms };
 
 static bool isElementRectMostlyInMainFrame(const HTMLMediaElement&);
@@ -109,6 +110,7 @@ MediaElementSession::MediaElementSession(HTMLMediaElement& element)
     , m_targetAvailabilityChangedTimer(*this, &MediaElementSession::targetAvailabilityChangedTimerFired)
 #endif
     , m_mainContentCheckTimer(*this, &MediaElementSession::mainContentCheckTimerFired)
+    , m_clientDataBufferingTimer(*this, &MediaElementSession::clientDataBufferingTimerFired)
 #if !RELEASE_LOG_DISABLED
     , m_logIdentifier(element.logIdentifier())
 #endif
@@ -133,6 +135,86 @@ void MediaElementSession::unregisterWithDocument(Document& document)
 #endif
 }
 
+void MediaElementSession::clientWillBeginAutoplaying()
+{
+    PlatformMediaSession::clientWillBeginAutoplaying();
+    m_elementIsHiddenBecauseItWasRemovedFromDOM = false;
+    updateClientDataBuffering();
+}
+
+bool MediaElementSession::clientWillBeginPlayback()
+{
+    if (!PlatformMediaSession::clientWillBeginPlayback())
+        return false;
+
+    m_elementIsHiddenBecauseItWasRemovedFromDOM = false;
+    updateClientDataBuffering();
+    return true;
+}
+
+bool MediaElementSession::clientWillPausePlayback()
+{
+    if (!PlatformMediaSession::clientWillPausePlayback())
+        return false;
+
+    updateClientDataBuffering();
+    return true;
+}
+
+void MediaElementSession::visibilityChanged()
+{
+    scheduleClientDataBufferingCheck();
+
+    if (m_element.elementIsHidden() && !m_element.isFullscreen())
+        m_elementIsHiddenUntilVisibleInViewport = true;
+}
+
+void MediaElementSession::isVisibleInViewportChanged()
+{
+    scheduleClientDataBufferingCheck();
+
+    if (m_element.isFullscreen() || m_element.isVisibleInViewport())
+        m_elementIsHiddenUntilVisibleInViewport = false;
+}
+
+void MediaElementSession::inActiveDocumentChanged()
+{
+    m_elementIsHiddenBecauseItWasRemovedFromDOM = !m_element.inActiveDocument();
+    scheduleClientDataBufferingCheck();
+}
+
+void MediaElementSession::scheduleClientDataBufferingCheck()
+{
+    if (!m_clientDataBufferingTimer.isActive())
+        m_clientDataBufferingTimer.startOneShot(clientDataBufferingTimerThrottleDelay);
+}
+
+void MediaElementSession::clientDataBufferingTimerFired()
+{
+    INFO_LOG(LOGIDENTIFIER, "visible = ", m_element.elementIsHidden());
+
+    updateClientDataBuffering();
+
+#if PLATFORM(IOS)
+    PlatformMediaSessionManager::sharedManager().configureWireLessTargetMonitoring();
+#endif
+
+    if (state() != Playing || !m_element.elementIsHidden())
+        return;
+
+    PlatformMediaSessionManager::SessionRestrictions restrictions = PlatformMediaSessionManager::sharedManager().restrictions(mediaType());
+    if ((restrictions & PlatformMediaSessionManager::BackgroundTabPlaybackRestricted) == PlatformMediaSessionManager::BackgroundTabPlaybackRestricted)
+        pauseSession();
+}
+
+void MediaElementSession::updateClientDataBuffering()
+{
+    if (m_clientDataBufferingTimer.isActive())
+        m_clientDataBufferingTimer.stop();
+
+    m_element.setShouldBufferData(dataBufferingPermitted());
+}
+
 void MediaElementSession::addBehaviorRestriction(BehaviorRestrictions restrictions)
 {
     if (restrictions & ~m_restrictions)
@@ -275,6 +357,23 @@ bool MediaElementSession::dataLoadingPermitted() const
     return true;
 }
 
+bool MediaElementSession::dataBufferingPermitted() const
+{
+    if (isSuspended())
+        return false;
+
+    if (state() == PlatformMediaSession::Playing)
+        return true;
+
+    if (shouldOverrideBackgroundLoadingRestriction())
+        return true;
+
+    if (m_elementIsHiddenUntilVisibleInViewport || m_elementIsHiddenBecauseItWasRemovedFromDOM || m_element.elementIsHidden())
+        return false;
+
+    return true;
+}
+
 bool MediaElementSession::fullscreenPermitted() const
 {
     if (m_restrictions & RequireUserGestureForFullscreen && !m_element.document().processingUserGestureForMedia()) {
@@ -418,9 +517,7 @@ bool MediaElementSession::wantsToObserveViewportVisibilityForMediaControls() con
 
 bool MediaElementSession::wantsToObserveViewportVisibilityForAutoplay() const
 {
-    if (!m_element.isVideo())
-        return false;
-    return hasBehaviorRestriction(InvisibleAutoplayNotPermitted) || hasBehaviorRestriction(OverrideUserGestureRequirementForMainContent);
+    return m_element.isVideo();
 }
 
 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
@@ -674,7 +771,7 @@ bool MediaElementSession::allowsPictureInPicture() const
 #if PLATFORM(IOS)
 bool MediaElementSession::requiresPlaybackTargetRouteMonitoring() const
 {
-    return m_hasPlaybackTargetAvailabilityListeners && !client().elementIsHidden();
+    return m_hasPlaybackTargetAvailabilityListeners && !m_element.elementIsHidden();
 }
 #endif
 
index 8289ffa..3e1f085 100644 (file)
@@ -61,9 +61,18 @@ public:
     void registerWithDocument(Document&);
     void unregisterWithDocument(Document&);
 
+    void clientWillBeginAutoplaying() final;
+    bool clientWillBeginPlayback() final;
+    bool clientWillPausePlayback() final;
+
+    void visibilityChanged();
+    void isVisibleInViewportChanged();
+    void inActiveDocumentChanged();
+
     SuccessOr<MediaPlaybackDenialReason> playbackPermitted() const;
     bool autoplayPermitted() const;
     bool dataLoadingPermitted() const;
+    bool dataBufferingPermitted() const;
     bool fullscreenPermitted() const;
     bool pageAllowsDataLoading() const;
     bool pageAllowsPlaybackAfterResuming() const;
@@ -165,9 +174,16 @@ private:
     bool updateIsMainContent() const;
     void mainContentCheckTimerFired();
 
+    void scheduleClientDataBufferingCheck();
+    void clientDataBufferingTimerFired();
+    void updateClientDataBuffering();
+
     HTMLMediaElement& m_element;
     BehaviorRestrictions m_restrictions;
 
+    bool m_elementIsHiddenUntilVisibleInViewport { false };
+    bool m_elementIsHiddenBecauseItWasRemovedFromDOM { false };
+
 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
     mutable Timer m_targetAvailabilityChangedTimer;
     RefPtr<MediaPlaybackTarget> m_playbackTarget;
@@ -182,6 +198,7 @@ private:
 
     mutable bool m_isMainContent { false };
     Timer m_mainContentCheckTimer;
+    Timer m_clientDataBufferingTimer;
 
 #if !RELEASE_LOG_DISABLED
     const void* m_logIdentifier;
index f2e1982..1de86e5 100644 (file)
@@ -93,7 +93,6 @@ std::unique_ptr<PlatformMediaSession> PlatformMediaSession::create(PlatformMedia
 
 PlatformMediaSession::PlatformMediaSession(PlatformMediaSessionClient& client)
     : m_client(client)
-    , m_clientDataBufferingTimer(*this, &PlatformMediaSession::clientDataBufferingTimerFired)
     , m_state(Idle)
     , m_stateToRestore(Idle)
     , m_notifyingClient(false)
@@ -176,7 +175,6 @@ void PlatformMediaSession::clientWillBeginAutoplaying()
     }
 
     setState(Autoplaying);
-    updateClientDataBuffering();
 }
 
 bool PlatformMediaSession::clientWillBeginPlayback()
@@ -191,7 +189,6 @@ bool PlatformMediaSession::clientWillBeginPlayback()
     }
 
     setState(Playing);
-    updateClientDataBuffering();
     return true;
 }
 
@@ -209,7 +206,6 @@ bool PlatformMediaSession::clientWillPausePlayback()
     
     setState(Paused);
     PlatformMediaSessionManager::sharedManager().sessionWillEndPlayback(*this);
-    scheduleClientDataBufferingCheck();
     return true;
 }
 
@@ -273,53 +269,11 @@ bool PlatformMediaSession::supportsSeeking() const
     return m_client.supportsSeeking();
 }
 
-void PlatformMediaSession::visibilityChanged()
-{
-    scheduleClientDataBufferingCheck();
-}
-
-void PlatformMediaSession::scheduleClientDataBufferingCheck()
-{
-    if (!m_clientDataBufferingTimer.isActive())
-        m_clientDataBufferingTimer.startOneShot(clientDataBufferingTimerThrottleDelay);
-}
-
-void PlatformMediaSession::clientDataBufferingTimerFired()
-{
-    INFO_LOG(LOGIDENTIFIER, "visible = ", m_client.elementIsHidden());
-
-    updateClientDataBuffering();
-
-#if PLATFORM(IOS)
-    PlatformMediaSessionManager::sharedManager().configureWireLessTargetMonitoring();
-#endif
-
-    if (m_state != Playing || !m_client.elementIsHidden())
-        return;
-
-    PlatformMediaSessionManager::SessionRestrictions restrictions = PlatformMediaSessionManager::sharedManager().restrictions(mediaType());
-    if ((restrictions & PlatformMediaSessionManager::BackgroundTabPlaybackRestricted) == PlatformMediaSessionManager::BackgroundTabPlaybackRestricted)
-        pauseSession();
-}
-
-void PlatformMediaSession::updateClientDataBuffering()
-{
-    if (m_clientDataBufferingTimer.isActive())
-        m_clientDataBufferingTimer.stop();
-
-    m_client.setShouldBufferData(PlatformMediaSessionManager::sharedManager().sessionCanLoadMedia(*this));
-}
-
 String PlatformMediaSession::sourceApplicationIdentifier() const
 {
     return m_client.sourceApplicationIdentifier();
 }
 
-bool PlatformMediaSession::isHidden() const
-{
-    return m_client.elementIsHidden();
-}
-
 bool PlatformMediaSession::isSuspended() const
 {
     return m_client.isSuspended();
index 838e347..037ff04 100644 (file)
@@ -105,15 +105,13 @@ public:
     void beginInterruption(InterruptionType);
     void endInterruption(EndInterruptionFlags);
 
-    void clientWillBeginAutoplaying();
-    bool clientWillBeginPlayback();
-    bool clientWillPausePlayback();
+    virtual void clientWillBeginAutoplaying();
+    virtual bool clientWillBeginPlayback();
+    virtual bool clientWillPausePlayback();
 
     void pauseSession();
     void stopSession();
     
-    void visibilityChanged();
-
 #if ENABLE(VIDEO)
     String title() const;
     double duration() const;
@@ -171,7 +169,6 @@ public:
     bool canProduceAudio() const;
     void canProduceAudioChanged();
 
-    void scheduleClientDataBufferingCheck();
     virtual void resetPlaybackSessionState() { }
     String sourceApplicationIdentifier() const;
 
@@ -188,11 +185,7 @@ protected:
 #endif
 
 private:
-    void clientDataBufferingTimerFired();
-    void updateClientDataBuffering();
-
     PlatformMediaSessionClient& m_client;
-    Timer m_clientDataBufferingTimer;
     State m_state;
     State m_stateToRestore;
     InterruptionType m_interruptionType { NoInterruption };
@@ -232,8 +225,6 @@ public:
     virtual void didReceiveRemoteControlCommand(PlatformMediaSession::RemoteControlCommandType, const PlatformMediaSession::RemoteCommandArgument*) = 0;
     virtual bool supportsSeeking() const = 0;
 
-    virtual void setShouldBufferData(bool) { }
-    virtual bool elementIsHidden() const { return false; }
     virtual bool canProduceAudio() const { return false; }
     virtual bool isSuspended() const { return false; };
 
index 806a3a5..3277b1a 100644 (file)
@@ -287,13 +287,6 @@ Vector<PlatformMediaSession*> PlatformMediaSessionManager::currentSessionsMatchi
     return matchingSessions;
 }
     
-bool PlatformMediaSessionManager::sessionCanLoadMedia(const PlatformMediaSession& session) const
-{
-    if (session.isSuspended())
-        return false;
-    return session.state() == PlatformMediaSession::Playing || !session.isHidden() || session.shouldOverrideBackgroundLoadingRestriction();
-}
-
 void PlatformMediaSessionManager::applicationWillBecomeInactive() const
 {
     LOG(Media, "PlatformMediaSessionManager::applicationWillBecomeInactive");
index 8a434d6..9897e6a 100644 (file)
@@ -94,7 +94,6 @@ public:
 
     virtual bool sessionWillBeginPlayback(PlatformMediaSession&);
     virtual void sessionWillEndPlayback(PlatformMediaSession&);
-    virtual bool sessionCanLoadMedia(const PlatformMediaSession&) const;
     virtual void sessionDidEndRemoteScrubbing(const PlatformMediaSession&) { };
     virtual void clientCharacteristicsChanged(PlatformMediaSession&) { }
 
index eb70dc2..ee193f4 100644 (file)
@@ -65,8 +65,6 @@ private:
 
     void configureWireLessTargetMonitoring() override;
 
-    bool sessionCanLoadMedia(const PlatformMediaSession&) const override;
-
     bool hasActiveNowPlayingSession() const final { return m_nowPlayingActive; }
     String lastUpdatedNowPlayingTitle() const final { return m_reportedTitle; }
     double lastUpdatedNowPlayingDuration() const final { return m_reportedDuration; }
index c8f435f..8b0bb34 100644 (file)
@@ -301,14 +301,6 @@ void MediaSessionManageriOS::updateNowPlayingInfo()
 #endif // HAVE(MEDIA_PLAYER)
 }
 
-bool MediaSessionManageriOS::sessionCanLoadMedia(const PlatformMediaSession& session) const
-{
-    if (session.displayType() == PlatformMediaSession::Optimized)
-        return true;
-
-    return PlatformMediaSessionManager::sessionCanLoadMedia(session);
-}
-
 void MediaSessionManageriOS::externalOutputDeviceAvailableDidChange()
 {
     BEGIN_BLOCK_OBJC_EXCEPTIONS
index 0289205..681b4cb 100644 (file)
@@ -64,6 +64,7 @@ RenderVideo::~RenderVideo()
 
 void RenderVideo::willBeDestroyed()
 {
+    visibleInViewportStateChanged();
     if (auto player = videoElement().player())
         player->setVisible(false);
 
index f3280d6..389903c 100644 (file)
@@ -3232,6 +3232,11 @@ void Internals::endSimulatedHDCPError(HTMLMediaElement& element)
         player->endSimulatedHDCPError();
 }
 
+bool Internals::elementShouldBufferData(HTMLMediaElement& element)
+{
+    return element.shouldBufferData();
+}
+
 #endif
 
 bool Internals::isSelectPopupVisible(HTMLSelectElement& element)
index 3a7dbc6..56fbd4a 100644 (file)
@@ -473,6 +473,8 @@ public:
     ExceptionOr<bool> mediaElementHasCharacteristic(HTMLMediaElement&, const String&);
     void beginSimulatedHDCPError(HTMLMediaElement&);
     void endSimulatedHDCPError(HTMLMediaElement&);
+
+    bool elementShouldBufferData(HTMLMediaElement&);
 #endif
 
     bool isSelectPopupVisible(HTMLSelectElement&);
index 52d2ee7..0c562d4 100644 (file)
@@ -429,6 +429,8 @@ enum EventThrottlingBehavior {
     [Conditional=VIDEO] void beginSimulatedHDCPError(HTMLMediaElement media);
     [Conditional=VIDEO] void endSimulatedHDCPError(HTMLMediaElement media);
 
+    [Conditional=VIDEO] boolean elementShouldBufferData(HTMLMediaElement media);
+
     [Conditional=LEGACY_ENCRYPTED_MEDIA] void initializeMockCDM();
     [Conditional=ENCRYPTED_MEDIA] MockCDMFactory registerMockCDM();