| Differences between
and this patch
- a/LayoutTests/ChangeLog +28 lines
Lines 1-3 a/LayoutTests/ChangeLog_sec1
1
2019-10-29  Peng Liu  <peng.liu6@apple.com>
2
3
        [Picture-in-Picture Web API] Implement PictureInPictureWindow
4
        https://bugs.webkit.org/show_bug.cgi?id=202615
5
6
        Reviewed by NOBODY (OOPS!).
7
8
        Add layout test cases for the Picture-in-Picture API.
9
10
        * TestExpectations:
11
        * media/picture-in-picture-api-enter-pip-1-expected.txt: Added.
12
        * media/picture-in-picture-api-enter-pip-1.html: Added.
13
        * media/picture-in-picture-api-enter-pip-2-expected.txt: Added.
14
        * media/picture-in-picture-api-enter-pip-2.html: Added.
15
        * media/picture-in-picture-api-enter-pip-3-expected.txt: Added.
16
        * media/picture-in-picture-api-enter-pip-3.html: Added.
17
        * media/picture-in-picture-api-enter-pip-4-expected.txt: Added.
18
        * media/picture-in-picture-api-enter-pip-4.html: Added.
19
        * media/picture-in-picture-api-exit-pip-1-expected.txt: Added.
20
        * media/picture-in-picture-api-exit-pip-1.html: Added.
21
        * media/picture-in-picture-api-exit-pip-2-expected.txt: Added.
22
        * media/picture-in-picture-api-exit-pip-2.html: Added.
23
        * media/picture-in-picture-api-pip-events-expected.txt: Added.
24
        * media/picture-in-picture-api-pip-events.html: Added.
25
        * media/picture-in-picture-api-pip-window-expected.txt: Added.
26
        * media/picture-in-picture-api-pip-window.html: Added.
27
        * platform/mac-wk2/TestExpectations:
28
1
2019-10-29  Wenson Hsieh  <wenson_hsieh@apple.com>
29
2019-10-29  Wenson Hsieh  <wenson_hsieh@apple.com>
2
30
3
        Unreviewed, add missing platform-specific test expectations after r251686
31
        Unreviewed, add missing platform-specific test expectations after r251686
- a/LayoutTests/TestExpectations +8 lines
Lines 195-200 webkit.org/b/202617 imported/w3c/web-platform-tests/picture-in-picture [ Skip ] a/LayoutTests/TestExpectations_sec1
195
195
196
# PiP API tests are only relevant on mac and iPad
196
# PiP API tests are only relevant on mac and iPad
197
media/picture-in-picture-api-element-attributes.html [ Skip ]
197
media/picture-in-picture-api-element-attributes.html [ Skip ]
198
media/picture-in-picture-api-enter-pip-1.html [ Skip ]
199
media/picture-in-picture-api-enter-pip-2.html [ Skip ]
200
media/picture-in-picture-api-enter-pip-3.html [ Skip ]
201
media/picture-in-picture-api-enter-pip-4.html [ Skip ]
202
media/picture-in-picture-api-exit-pip-1.html [ Skip ]
203
media/picture-in-picture-api-exit-pip-2.html [ Skip ]
204
media/picture-in-picture-api-pip-events.html [ Skip ]
205
media/picture-in-picture-api-pip-window.html [ Skip ]
198
206
199
# Shared Workers are unsupported
207
# Shared Workers are unsupported
200
imported/w3c/web-platform-tests/secure-contexts/basic-shared-worker.html [ Skip ]
208
imported/w3c/web-platform-tests/secure-contexts/basic-shared-worker.html [ Skip ]
- a/LayoutTests/media/picture-in-picture-api-enter-pip-1-expected.txt +8 lines
Line 0 a/LayoutTests/media/picture-in-picture-api-enter-pip-1-expected.txt_sec1
1
This tests that request Picture-in-Picture requires a user gesture.
2
3
RUN(internals.settings.setAllowsPictureInPictureMediaPlayback(true))
4
RUN(video.src = findMediaFile("video", "content/test"))
5
EVENT(canplaythrough)
6
EXPECTED (error.name == 'NotAllowedError') OK
7
END OF TEST
8
- a/LayoutTests/media/picture-in-picture-api-enter-pip-1.html +30 lines
Line 0 a/LayoutTests/media/picture-in-picture-api-enter-pip-1.html_sec1
1
<!DOCTYPE html>
2
<html>
3
<head>
4
    <script src="video-test.js"></script>
5
    <script src="media-file.js"></script>
6
    <script>
7
        window.addEventListener('load', async event => {
8
            findMediaElement();
9
10
            run('internals.settings.setAllowsPictureInPictureMediaPlayback(true)');
11
            run('video.src = findMediaFile("video", "content/test")');
12
            await waitFor(video, 'canplaythrough');
13
14
            video.requestPictureInPicture()
15
            .then(() => {
16
                failTest("request Picture-in-Picture requires a user gesture.");
17
            })
18
            .catch(error => {
19
                window.error = error;
20
                testExpected('error.name', 'NotAllowedError');
21
                endTest();
22
            });
23
        });
24
    </script>
25
</head>
26
<body>
27
    <div>This tests that request Picture-in-Picture requires a user gesture.</div>
28
    <video controls></video>
29
</body>
30
</html>
- a/LayoutTests/media/picture-in-picture-api-enter-pip-2-expected.txt +6 lines
Line 0 a/LayoutTests/media/picture-in-picture-api-enter-pip-2-expected.txt_sec1
1
This tests that request Picture-in-Picture requires loaded metadata for the video element.
2
3
RUN(internals.settings.setAllowsPictureInPictureMediaPlayback(true))
4
EXPECTED (error.name == 'InvalidStateError') OK
5
END OF TEST
6
- a/LayoutTests/media/picture-in-picture-api-enter-pip-2.html +29 lines
Line 0 a/LayoutTests/media/picture-in-picture-api-enter-pip-2.html_sec1
1
<!DOCTYPE html>
2
<html>
3
<head>
4
    <script src="video-test.js"></script>
5
    <script src="media-file.js"></script>
6
    <script>
7
        window.addEventListener('load', async event => {
8
            findMediaElement();
9
10
            run('internals.settings.setAllowsPictureInPictureMediaPlayback(true)');
11
            runWithKeyDown(function() {
12
                video.requestPictureInPicture()
13
                .then(() => {
14
                    failTest('request Picture-in-Picture requires loaded metadata for the video element.')
15
                })
16
                .catch(error => {
17
                    window.error = error;
18
                    testExpected('error.name', 'InvalidStateError');
19
                    endTest();
20
                });
21
            });
22
        });
23
    </script>
24
</head>
25
<body>
26
    <div>This tests that request Picture-in-Picture requires loaded metadata for the video element.</div>
27
    <video controls></video>
28
</body>
29
</html>
- a/LayoutTests/media/picture-in-picture-api-enter-pip-3-expected.txt +8 lines
Line 0 a/LayoutTests/media/picture-in-picture-api-enter-pip-3-expected.txt_sec1
1
This tests that request Picture-in-Picture requires video track for the video element.
2
3
RUN(internals.settings.setAllowsPictureInPictureMediaPlayback(true))
4
RUN(video.src = findMediaFile("audio", "content/test"))
5
EVENT(canplaythrough)
6
EXPECTED (error.name == 'InvalidStateError') OK
7
END OF TEST
8
- a/LayoutTests/media/picture-in-picture-api-enter-pip-3.html +31 lines
Line 0 a/LayoutTests/media/picture-in-picture-api-enter-pip-3.html_sec1
1
<!DOCTYPE html>
2
<html>
3
<head>
4
    <script src="video-test.js"></script>
5
    <script src="media-file.js"></script>
6
    <script>
7
        window.addEventListener('load', async event => {
8
            findMediaElement();
9
10
            run('internals.settings.setAllowsPictureInPictureMediaPlayback(true)');
11
            run('video.src = findMediaFile("audio", "content/test")');
12
            await waitFor(video, 'canplaythrough');
13
            runWithKeyDown(function() {
14
                video.requestPictureInPicture()
15
                .then(() => {
16
                    failTest('request Picture-in-Picture requires video track for the video element.')
17
                })
18
                .catch(error => {
19
                    window.error = error;
20
                    testExpected('error.name', 'InvalidStateError');
21
                    endTest();
22
                });
23
            });
24
        });
25
    </script>
26
</head>
27
<body>
28
    <div>This tests that request Picture-in-Picture requires video track for the video element.</div>
29
    <video controls></video>
30
</body>
31
</html>
- a/LayoutTests/media/picture-in-picture-api-enter-pip-4-expected.txt +7 lines
Line 0 a/LayoutTests/media/picture-in-picture-api-enter-pip-4-expected.txt_sec1
1
This tests that request Picture-in-Picture resolves on user click.
2
3
RUN(internals.settings.setAllowsPictureInPictureMediaPlayback(true))
4
RUN(video.src = findMediaFile("video", "content/test"))
5
EVENT(canplaythrough)
6
END OF TEST
7
- a/LayoutTests/media/picture-in-picture-api-enter-pip-4.html +29 lines
Line 0 a/LayoutTests/media/picture-in-picture-api-enter-pip-4.html_sec1
1
<!DOCTYPE html>
2
<html>
3
<head>
4
    <script src="video-test.js"></script>
5
    <script src="media-file.js"></script>
6
    <script>
7
        window.addEventListener('load', async event => {
8
            findMediaElement();
9
10
            run('internals.settings.setAllowsPictureInPictureMediaPlayback(true)');
11
            run('video.src = findMediaFile("video", "content/test")');
12
            await waitFor(video, 'canplaythrough');
13
            runWithKeyDown(function() {
14
                video.requestPictureInPicture()
15
                .then(() => {
16
                    endTest();
17
                })
18
                .catch(() => {
19
                    failTest('request Picture-in-Picture does not resolve on user click.');
20
                });
21
            });
22
        });
23
    </script>
24
</head>
25
<body>
26
    <div>This tests that request Picture-in-Picture resolves on user click.</div>
27
    <video controls></video>
28
</body>
29
</html>
- a/LayoutTests/media/picture-in-picture-api-exit-pip-1-expected.txt +8 lines
Line 0 a/LayoutTests/media/picture-in-picture-api-exit-pip-1-expected.txt_sec1
1
This tests that exit Picture-in-Picture resolves when there is a Picture-in-Picture video.
2
3
RUN(internals.settings.setAllowsPictureInPictureMediaPlayback(true))
4
RUN(video.src = findMediaFile("video", "content/test"))
5
EVENT(canplaythrough)
6
EVENT(enterpictureinpicture)
7
END OF TEST
8
- a/LayoutTests/media/picture-in-picture-api-exit-pip-1.html +31 lines
Line 0 a/LayoutTests/media/picture-in-picture-api-exit-pip-1.html_sec1
1
<!DOCTYPE html>
2
<html>
3
<head>
4
    <script src="video-test.js"></script>
5
    <script src="media-file.js"></script>
6
    <script>
7
        window.addEventListener('load', async event => {
8
            findMediaElement();
9
10
            run('internals.settings.setAllowsPictureInPictureMediaPlayback(true)');
11
            run('video.src = findMediaFile("video", "content/test")');
12
            await waitFor(video, 'canplaythrough');
13
            runWithKeyDown(function() { video.requestPictureInPicture() });
14
            await waitFor(video, 'enterpictureinpicture');
15
            runWithKeyDown(function() {
16
                document.exitPictureInPicture()
17
                .then(() => {
18
                    endTest();
19
                })
20
                .catch(() => {
21
                    failTest('Exit Picture-in-Picture resolves when there is a Picture-in-Picture video.')
22
                });
23
            });
24
        });
25
    </script>
26
</head>
27
<body>
28
    <div>This tests that exit Picture-in-Picture resolves when there is a Picture-in-Picture video.</div>
29
    <video controls></video>
30
</body>
31
</html>
- a/LayoutTests/media/picture-in-picture-api-exit-pip-2-expected.txt +5 lines
Line 0 a/LayoutTests/media/picture-in-picture-api-exit-pip-2-expected.txt_sec1
1
This tests that exit Picture-in-Picture rejects when there is no Picture-in-Picture video.
2
3
EXPECTED (error.name == 'InvalidStateError') OK
4
END OF TEST
5
- a/LayoutTests/media/picture-in-picture-api-exit-pip-2.html +27 lines
Line 0 a/LayoutTests/media/picture-in-picture-api-exit-pip-2.html_sec1
1
<!DOCTYPE html>
2
<html>
3
<head>
4
    <script src="video-test.js"></script>
5
    <script src="media-file.js"></script>
6
    <script>
7
        window.addEventListener('load', async event => {
8
            findMediaElement();
9
            runWithKeyDown(function() {
10
                document.exitPictureInPicture()
11
                .then(() => {
12
                    failTest('Exit Picture-in-Picture rejects when there is no Picture-in-Picture video.');
13
                })
14
                .catch(error => {
15
                    window.error = error;
16
                    testExpected('error.name', 'InvalidStateError');
17
                    endTest();
18
                });
19
            });
20
        });
21
    </script>
22
</head>
23
<body>
24
    <div>This tests that exit Picture-in-Picture rejects when there is no Picture-in-Picture video.</div>
25
    <video controls></video>
26
</body>
27
</html>
- a/LayoutTests/media/picture-in-picture-api-pip-events-expected.txt +11 lines
Line 0 a/LayoutTests/media/picture-in-picture-api-pip-events-expected.txt_sec1
1
This tests that events are fired correctly when a video element enters and exits the Picture-in-Picture mode.
2
3
RUN(internals.settings.setAllowsPictureInPictureMediaPlayback(true))
4
RUN(video.src = findMediaFile("video", "content/test"))
5
EVENT(canplaythrough)
6
RUN(video.play())
7
EVENT(playing)
8
EVENT(enterpictureinpicture)
9
EVENT(leavepictureinpicture)
10
END OF TEST
11
- a/LayoutTests/media/picture-in-picture-api-pip-events.html +32 lines
Line 0 a/LayoutTests/media/picture-in-picture-api-pip-events.html_sec1
1
<!DOCTYPE html>
2
<html>
3
<head>
4
    <script src="video-test.js"></script>
5
    <script src="media-file.js"></script>
6
    <script>
7
        window.addEventListener('load', async event => {
8
            findMediaElement();
9
10
            run('internals.settings.setAllowsPictureInPictureMediaPlayback(true)');
11
12
            run('video.src = findMediaFile("video", "content/test")');
13
            await waitFor(video, 'canplaythrough');
14
15
            run('video.play()');
16
            await waitFor(video, 'playing');
17
18
            runWithKeyDown(function() { video.requestPictureInPicture(); });
19
            await waitFor(video, 'enterpictureinpicture');
20
21
            runWithKeyDown(function() { document.exitPictureInPicture(); });
22
            await waitFor(video, 'leavepictureinpicture');
23
24
            endTest();
25
        });
26
    </script>
27
</head>
28
<body>
29
    <div>This tests that events are fired correctly when a video element enters and exits the Picture-in-Picture mode.</div>
30
    <video controls></video>
31
</body>
32
</html>
- a/LayoutTests/media/picture-in-picture-api-pip-window-expected.txt +11 lines
Line 0 a/LayoutTests/media/picture-in-picture-api-pip-window-expected.txt_sec1
1
This tests that a pip window is returned correctly when a video element enters the Picture-in-Picture mode.
2
3
RUN(internals.settings.setAllowsPictureInPictureMediaPlayback(true))
4
RUN(video.src = findMediaFile("video", "content/test"))
5
EVENT(canplaythrough)
6
RUN(video.play())
7
EVENT(playing)
8
EXPECTED (pipWindow.width > '0') OK
9
EXPECTED (pipWindow.height > '0') OK
10
END OF TEST
11
- a/LayoutTests/media/picture-in-picture-api-pip-window.html +37 lines
Line 0 a/LayoutTests/media/picture-in-picture-api-pip-window.html_sec1
1
<!DOCTYPE html>
2
<html>
3
<head>
4
    <script src="video-test.js"></script>
5
    <script src="media-file.js"></script>
6
    <script>
7
        window.addEventListener('load', async event => {
8
            findMediaElement();
9
10
            run('internals.settings.setAllowsPictureInPictureMediaPlayback(true)');
11
12
            run('video.src = findMediaFile("video", "content/test")');
13
            await waitFor(video, 'canplaythrough');
14
15
            run('video.play()');
16
            await waitFor(video, 'playing');
17
18
            runWithKeyDown(function() {
19
                video.requestPictureInPicture()
20
                .then(pipWindow => {
21
                    window.pipWindow = pipWindow;
22
                    testExpected('pipWindow.width', 0, '>');
23
                    testExpected('pipWindow.height', 0, '>');
24
                    endTest();
25
                })
26
                .catch(error => {
27
                    failTest("Failed to enter the Picture-in-Picture mode.");
28
                });
29
            });
30
        });
31
    </script>
32
</head>
33
<body>
34
    <div>This tests that a pip window is returned correctly when a video element enters the Picture-in-Picture mode.</div>
35
    <video controls></video>
36
</body>
37
</html>
- a/LayoutTests/platform/mac-wk2/TestExpectations +8 lines
Lines 542-547 webkit.org/b/172998 [ Sierra+ ] media/fullscreen-api-enabled-media-with-presenta a/LayoutTests/platform/mac-wk2/TestExpectations_sec1
542
webkit.org/b/173199 [ Sierra+ ] media/navigate-with-pip-should-not-crash.html [ Pass Failure ]
542
webkit.org/b/173199 [ Sierra+ ] media/navigate-with-pip-should-not-crash.html [ Pass Failure ]
543
[ Sierra+ ] media/pip-video-going-into-fullscreen.html [ Pass ]
543
[ Sierra+ ] media/pip-video-going-into-fullscreen.html [ Pass ]
544
[ Sierra+ ] media/picture-in-picture-api-element-attributes.html [ Pass ]
544
[ Sierra+ ] media/picture-in-picture-api-element-attributes.html [ Pass ]
545
[ Sierra+ ] media/picture-in-picture-api-enter-pip-1.html [ Pass ]
546
[ Sierra+ ] media/picture-in-picture-api-enter-pip-2.html [ Pass ]
547
[ Sierra+ ] media/picture-in-picture-api-enter-pip-3.html [ Pass ]
548
[ Sierra+ ] media/picture-in-picture-api-enter-pip-4.html [ Pass ]
549
[ Sierra+ ] media/picture-in-picture-api-exit-pip-1.html [ Pass ]
550
[ Sierra+ ] media/picture-in-picture-api-exit-pip-2.html [ Pass ]
551
[ Sierra+ ] media/picture-in-picture-api-pip-events.html [ Pass ]
552
[ Sierra+ ] media/picture-in-picture-api-pip-window.html [ Pass ]
545
553
546
# RTL Scrollbars are enabled on Sierra WebKit2.
554
# RTL Scrollbars are enabled on Sierra WebKit2.
547
webkit.org/b/179455 [ Sierra+ ] fast/scrolling/rtl-scrollbars.html [ Pass ImageOnlyFailure ]
555
webkit.org/b/179455 [ Sierra+ ] fast/scrolling/rtl-scrollbars.html [ Pass ImageOnlyFailure ]
- a/Source/WebCore/ChangeLog +37 lines
Lines 1-3 a/Source/WebCore/ChangeLog_sec1
1
2019-10-29  Peng Liu  <peng.liu6@apple.com>
2
3
        [Picture-in-Picture Web API] Implement PictureInPictureWindow
4
        https://bugs.webkit.org/show_bug.cgi?id=202615
5
6
        Reviewed by NOBODY (OOPS!).
7
8
        Tests: media/picture-in-picture-api-enter-pip-1.html
9
               media/picture-in-picture-api-enter-pip-2.html
10
               media/picture-in-picture-api-enter-pip-3.html
11
               media/picture-in-picture-api-enter-pip-4.html
12
               media/picture-in-picture-api-exit-pip-1.html
13
               media/picture-in-picture-api-exit-pip-2.html
14
               media/picture-in-picture-api-pip-events.html
15
               media/picture-in-picture-api-pip-window.html
16
17
        * Modules/pictureinpicture/HTMLVideoElementPictureInPicture.cpp:
18
        (WebCore::HTMLVideoElementPictureInPicture::HTMLVideoElementPictureInPicture):
19
        (WebCore::HTMLVideoElementPictureInPicture::requestPictureInPicture):
20
        (WebCore::HTMLVideoElementPictureInPicture::didEnterPictureInPicture):
21
        (WebCore::HTMLVideoElementPictureInPicture::didExitPictureInPicture):
22
        (WebCore::HTMLVideoElementPictureInPicture::pictureInPictureWindowResized):
23
        * Modules/pictureinpicture/HTMLVideoElementPictureInPicture.h:
24
        * Modules/pictureinpicture/PictureInPictureWindow.cpp:
25
        (WebCore::PictureInPictureWindow::create):
26
        (WebCore::PictureInPictureWindow::PictureInPictureWindow):
27
        (WebCore::PictureInPictureWindow::setSize):
28
        (WebCore::PictureInPictureWindow::close):
29
        * Modules/pictureinpicture/PictureInPictureWindow.h:
30
        * html/HTMLVideoElement.cpp:
31
        (WebCore::HTMLVideoElement::fullscreenModeChanged):
32
        (WebCore::HTMLVideoElement::didBecomeFullscreenElement):
33
        (WebCore::HTMLVideoElement::setPictureInPictureObserver):
34
        (WebCore::HTMLVideoElement::setVideoFullscreenFrame):
35
        * html/HTMLVideoElement.h:
36
        * platform/PictureInPictureObserver.h:
37
1
2019-10-29  Antoine Quint  <graouts@apple.com>
38
2019-10-29  Antoine Quint  <graouts@apple.com>
2
39
3
        [Web Animations] Optimize blending for CSS Transitions
40
        [Web Animations] Optimize blending for CSS Transitions
- a/Source/WebCore/Modules/pictureinpicture/HTMLVideoElementPictureInPicture.cpp -16 / +22 lines
Lines 31-36 a/Source/WebCore/Modules/pictureinpicture/HTMLVideoElementPictureInPicture.cpp_sec1
31
31
32
#include "HTMLVideoElement.h"
32
#include "HTMLVideoElement.h"
33
#include "JSDOMPromiseDeferred.h"
33
#include "JSDOMPromiseDeferred.h"
34
#include "JSPictureInPictureWindow.h"
34
#include "Logging.h"
35
#include "Logging.h"
35
#include "PictureInPictureWindow.h"
36
#include "PictureInPictureWindow.h"
36
#include "VideoTrackList.h"
37
#include "VideoTrackList.h"
Lines 42-47 WTF_MAKE_ISO_ALLOCATED_IMPL(HTMLVideoElementPictureInPicture); a/Source/WebCore/Modules/pictureinpicture/HTMLVideoElementPictureInPicture.cpp_sec2
42
43
43
HTMLVideoElementPictureInPicture::HTMLVideoElementPictureInPicture(HTMLVideoElement& videoElement)
44
HTMLVideoElementPictureInPicture::HTMLVideoElementPictureInPicture(HTMLVideoElement& videoElement)
44
    : m_videoElement(videoElement)
45
    : m_videoElement(videoElement)
46
    , m_pictureInPictureWindow(PictureInPictureWindow::create(videoElement.document()))
45
#if !RELEASE_LOG_DISABLED
47
#if !RELEASE_LOG_DISABLED
46
    , m_logger(videoElement.document().logger())
48
    , m_logger(videoElement.document().logger())
47
    , m_logIdentifier(uniqueLogIdentifier())
49
    , m_logIdentifier(uniqueLogIdentifier())
Lines 70-80 HTMLVideoElementPictureInPicture* HTMLVideoElementPictureInPicture::from(HTMLVid a/Source/WebCore/Modules/pictureinpicture/HTMLVideoElementPictureInPicture.cpp_sec3
70
72
71
void HTMLVideoElementPictureInPicture::requestPictureInPicture(HTMLVideoElement& videoElement, Ref<DeferredPromise>&& promise)
73
void HTMLVideoElementPictureInPicture::requestPictureInPicture(HTMLVideoElement& videoElement, Ref<DeferredPromise>&& promise)
72
{
74
{
73
    if (!videoElement.player() || !videoElement.player()->supportsPictureInPicture()) {
74
        promise->reject(NotSupportedError, "The video element does not support the Picture-in-Picture mode.");
75
        return;
76
    }
77
78
    if (videoElement.readyState() == HTMLMediaElementEnums::HAVE_NOTHING) {
75
    if (videoElement.readyState() == HTMLMediaElementEnums::HAVE_NOTHING) {
79
        promise->reject(InvalidStateError, "The video element is not ready to enter the Picture-in-Picture mode.");
76
        promise->reject(InvalidStateError, "The video element is not ready to enter the Picture-in-Picture mode.");
80
        return;
77
        return;
Lines 93-104 void HTMLVideoElementPictureInPicture::requestPictureInPicture(HTMLVideoElement& a/Source/WebCore/Modules/pictureinpicture/HTMLVideoElementPictureInPicture.cpp_sec4
93
        return;
90
        return;
94
    }
91
    }
95
92
93
    auto videoElementPictureInPicture = HTMLVideoElementPictureInPicture::from(videoElement);
96
    if (videoElement.document().pictureInPictureElement() == &videoElement) {
94
    if (videoElement.document().pictureInPictureElement() == &videoElement) {
97
        promise->reject(NotAllowedError, "The video element is already in the Picture-in-Picture mode.");
95
        promise->resolve<IDLInterface<PictureInPictureWindow>>(*(videoElementPictureInPicture->m_pictureInPictureWindow));
98
        return;
96
        return;
99
    }
97
    }
100
98
101
    auto videoElementPictureInPicture = HTMLVideoElementPictureInPicture::from(videoElement);
102
    if (videoElementPictureInPicture->m_enterPictureInPicturePromise || videoElementPictureInPicture->m_exitPictureInPicturePromise) {
99
    if (videoElementPictureInPicture->m_enterPictureInPicturePromise || videoElementPictureInPicture->m_exitPictureInPicturePromise) {
103
        promise->reject(NotAllowedError, "The video element is processing a Picture-in-Picture request.");
100
        promise->reject(NotAllowedError, "The video element is processing a Picture-in-Picture request.");
104
        return;
101
        return;
Lines 143-159 void HTMLVideoElementPictureInPicture::exitPictureInPicture(Ref<DeferredPromise> a/Source/WebCore/Modules/pictureinpicture/HTMLVideoElementPictureInPicture.cpp_sec5
143
    m_videoElement.webkitSetPresentationMode(HTMLVideoElement::VideoPresentationMode::Inline);
140
    m_videoElement.webkitSetPresentationMode(HTMLVideoElement::VideoPresentationMode::Inline);
144
}
141
}
145
142
146
void HTMLVideoElementPictureInPicture::didEnterPictureInPicture(IntSize windowSize)
143
void HTMLVideoElementPictureInPicture::didEnterPictureInPicture(const IntSize& windowSize)
147
{
144
{
148
    INFO_LOG(LOGIDENTIFIER);
145
    INFO_LOG(LOGIDENTIFIER);
149
    m_videoElement.document().setPictureInPictureElement(&m_videoElement);
146
    m_videoElement.document().setPictureInPictureElement(&m_videoElement);
147
    m_pictureInPictureWindow->setSize(windowSize);
148
150
    if (m_enterPictureInPicturePromise) {
149
    if (m_enterPictureInPicturePromise) {
151
        EnterPictureInPictureEvent::Init initializer;
150
        EnterPictureInPictureEvent::Init initializer;
152
        initializer.bubbles = true;
151
        initializer.bubbles = true;
153
        initializer.pictureInPictureWindow = PictureInPictureWindow::create(m_videoElement.document(), windowSize.width(), windowSize.height());
152
        initializer.pictureInPictureWindow = m_pictureInPictureWindow;
154
        m_videoElement.scheduleEvent(EnterPictureInPictureEvent::create(eventNames().enterpictureinpictureEvent, WTFMove(initializer)));
153
        m_videoElement.scheduleEvent(EnterPictureInPictureEvent::create(eventNames().enterpictureinpictureEvent, WTFMove(initializer)));
155
154
        m_enterPictureInPicturePromise->resolve<IDLInterface<PictureInPictureWindow>>(*m_pictureInPictureWindow);
156
        m_enterPictureInPicturePromise->resolve();
157
        m_enterPictureInPicturePromise = nullptr;
155
        m_enterPictureInPicturePromise = nullptr;
158
    }
156
    }
159
}
157
}
Lines 161-175 void HTMLVideoElementPictureInPicture::didEnterPictureInPicture(IntSize windowSi a/Source/WebCore/Modules/pictureinpicture/HTMLVideoElementPictureInPicture.cpp_sec6
161
void HTMLVideoElementPictureInPicture::didExitPictureInPicture()
159
void HTMLVideoElementPictureInPicture::didExitPictureInPicture()
162
{
160
{
163
    INFO_LOG(LOGIDENTIFIER);
161
    INFO_LOG(LOGIDENTIFIER);
162
    m_pictureInPictureWindow->close();
164
    m_videoElement.document().setPictureInPictureElement(nullptr);
163
    m_videoElement.document().setPictureInPictureElement(nullptr);
164
165
    if (m_exitPictureInPicturePromise) {
165
    if (m_exitPictureInPicturePromise) {
166
        m_videoElement.scheduleEvent(Event::create(eventNames().leavepictureinpictureEvent, Event::CanBubble::Yes, Event::IsCancelable::No));
166
        m_videoElement.scheduleEvent(Event::create(eventNames().leavepictureinpictureEvent, Event::CanBubble::Yes, Event::IsCancelable::No));
167
168
        m_exitPictureInPicturePromise->resolve();
167
        m_exitPictureInPicturePromise->resolve();
169
        m_exitPictureInPicturePromise = nullptr;
168
        m_exitPictureInPicturePromise = nullptr;
170
    }
169
    }
171
}
170
}
172
171
172
void HTMLVideoElementPictureInPicture::pictureInPictureWindowResized(const IntSize& windowSize)
173
{
174
    if (m_pictureInPictureWindow->width() == windowSize.width() && m_pictureInPictureWindow->height() == windowSize.height())
175
        return;
176
177
    m_pictureInPictureWindow->setSize(windowSize);
178
    auto resizeEvent = Event::create(eventNames().resizeEvent, Event::CanBubble::Yes, Event::IsCancelable::No);
179
    resizeEvent->setTarget(m_pictureInPictureWindow);
180
    m_videoElement.scheduleEvent(WTFMove(resizeEvent));
181
}
182
173
#if !RELEASE_LOG_DISABLED
183
#if !RELEASE_LOG_DISABLED
174
WTFLogChannel& HTMLVideoElementPictureInPicture::logChannel() const
184
WTFLogChannel& HTMLVideoElementPictureInPicture::logChannel() const
175
{
185
{
Lines 177-186 WTFLogChannel& HTMLVideoElementPictureInPicture::logChannel() const a/Source/WebCore/Modules/pictureinpicture/HTMLVideoElementPictureInPicture.cpp_sec7
177
}
187
}
178
#endif
188
#endif
179
189
180
void HTMLVideoElementPictureInPicture::pictureInPictureWindowResized(IntSize)
181
{
182
}
183
184
} // namespace WebCore
190
} // namespace WebCore
185
191
186
#endif // ENABLE(PICTURE_IN_PICTURE_API)
192
#endif // ENABLE(PICTURE_IN_PICTURE_API)
- a/Source/WebCore/Modules/pictureinpicture/HTMLVideoElementPictureInPicture.h -2 / +3 lines
Lines 60-68 public: a/Source/WebCore/Modules/pictureinpicture/HTMLVideoElementPictureInPicture.h_sec1
60
60
61
    void exitPictureInPicture(Ref<DeferredPromise>&&);
61
    void exitPictureInPicture(Ref<DeferredPromise>&&);
62
62
63
    void didEnterPictureInPicture(IntSize);
63
    void didEnterPictureInPicture(const IntSize&);
64
    void didExitPictureInPicture();
64
    void didExitPictureInPicture();
65
    void pictureInPictureWindowResized(IntSize);
65
    void pictureInPictureWindowResized(const IntSize&);
66
66
67
#if !RELEASE_LOG_DISABLED
67
#if !RELEASE_LOG_DISABLED
68
    const Logger& logger() const final { return m_logger.get(); }
68
    const Logger& logger() const final { return m_logger.get(); }
Lines 78-83 private: a/Source/WebCore/Modules/pictureinpicture/HTMLVideoElementPictureInPicture.h_sec2
78
    bool m_disablePictureInPicture { false };
78
    bool m_disablePictureInPicture { false };
79
79
80
    HTMLVideoElement& m_videoElement;
80
    HTMLVideoElement& m_videoElement;
81
    RefPtr<PictureInPictureWindow> m_pictureInPictureWindow;
81
    RefPtr<DeferredPromise> m_enterPictureInPicturePromise;
82
    RefPtr<DeferredPromise> m_enterPictureInPicturePromise;
82
    RefPtr<DeferredPromise> m_exitPictureInPicturePromise;
83
    RefPtr<DeferredPromise> m_exitPictureInPicturePromise;
83
84
- a/Source/WebCore/Modules/pictureinpicture/PictureInPictureWindow.cpp -5 / +13 lines
Lines 35-54 namespace WebCore { a/Source/WebCore/Modules/pictureinpicture/PictureInPictureWindow.cpp_sec1
35
35
36
WTF_MAKE_ISO_ALLOCATED_IMPL(PictureInPictureWindow);
36
WTF_MAKE_ISO_ALLOCATED_IMPL(PictureInPictureWindow);
37
37
38
Ref<PictureInPictureWindow> PictureInPictureWindow::create(ScriptExecutionContext& scriptExecutionContext, int width, int height)
38
Ref<PictureInPictureWindow> PictureInPictureWindow::create(ScriptExecutionContext& scriptExecutionContext)
39
{
39
{
40
    return adoptRef(*new PictureInPictureWindow(scriptExecutionContext, width, height));
40
    return adoptRef(*new PictureInPictureWindow(scriptExecutionContext));
41
}
41
}
42
42
43
PictureInPictureWindow::PictureInPictureWindow(ScriptExecutionContext& scriptExecutionContext, int width, int height)
43
PictureInPictureWindow::PictureInPictureWindow(ScriptExecutionContext& scriptExecutionContext)
44
    : m_scriptExecutionContext(scriptExecutionContext)
44
    : m_scriptExecutionContext(scriptExecutionContext)
45
    , m_width(width)
46
    , m_height(height)
47
{
45
{
48
}
46
}
49
47
50
PictureInPictureWindow::~PictureInPictureWindow() = default;
48
PictureInPictureWindow::~PictureInPictureWindow() = default;
51
49
50
void PictureInPictureWindow::setSize(const IntSize& size)
51
{
52
    m_size = size;
53
}
54
55
void PictureInPictureWindow::close()
56
{
57
    m_size = { 0, 0 };
58
}
59
52
} // namespace WebCore
60
} // namespace WebCore
53
61
54
#endif // ENABLE(PICTURE_IN_PICTURE_API)
62
#endif // ENABLE(PICTURE_IN_PICTURE_API)
- a/Source/WebCore/Modules/pictureinpicture/PictureInPictureWindow.h -6 / +7 lines
Lines 38-54 class PictureInPictureWindow final a/Source/WebCore/Modules/pictureinpicture/PictureInPictureWindow.h_sec1
38
    , public EventTargetWithInlineData {
38
    , public EventTargetWithInlineData {
39
    WTF_MAKE_ISO_ALLOCATED(PictureInPictureWindow);
39
    WTF_MAKE_ISO_ALLOCATED(PictureInPictureWindow);
40
public:
40
public:
41
    static Ref<PictureInPictureWindow> create(ScriptExecutionContext&, int, int);
41
    static Ref<PictureInPictureWindow> create(ScriptExecutionContext&);
42
    virtual ~PictureInPictureWindow();
42
    virtual ~PictureInPictureWindow();
43
43
44
    int width() const { return m_width; }
44
    int width() const { return m_size.width(); }
45
    int height() const { return m_height; }
45
    int height() const { return m_size.height(); }
46
    void setSize(const IntSize&);
47
    void close();
46
48
47
    using RefCounted<PictureInPictureWindow>::ref;
49
    using RefCounted<PictureInPictureWindow>::ref;
48
    using RefCounted<PictureInPictureWindow>::deref;
50
    using RefCounted<PictureInPictureWindow>::deref;
49
51
50
private:
52
private:
51
    PictureInPictureWindow(ScriptExecutionContext&, int, int);
53
    PictureInPictureWindow(ScriptExecutionContext&);
52
54
53
    // EventTarget
55
    // EventTarget
54
    void refEventTarget() final { ref(); }
56
    void refEventTarget() final { ref(); }
Lines 57-64 private: a/Source/WebCore/Modules/pictureinpicture/PictureInPictureWindow.h_sec2
57
    ScriptExecutionContext* scriptExecutionContext() const override { return &m_scriptExecutionContext; };
59
    ScriptExecutionContext* scriptExecutionContext() const override { return &m_scriptExecutionContext; };
58
60
59
    ScriptExecutionContext& m_scriptExecutionContext;
61
    ScriptExecutionContext& m_scriptExecutionContext;
60
    int m_width;
62
    IntSize m_size;
61
    int m_height;
62
};
63
};
63
64
64
} // namespace WebCore
65
} // namespace WebCore
- a/Source/WebCore/html/HTMLVideoElement.cpp -2 / +9 lines
Lines 492-499 void HTMLVideoElement::fullscreenModeChanged(VideoFullscreenMode mode) a/Source/WebCore/html/HTMLVideoElement.cpp_sec1
492
            HTMLVideoElement::VideoPresentationMode targetVideoPresentationMode = toPresentationMode(mode);
492
            HTMLVideoElement::VideoPresentationMode targetVideoPresentationMode = toPresentationMode(mode);
493
            HTMLVideoElement::VideoPresentationMode sourceVideoPresentationMode = toPresentationMode(fullscreenMode());
493
            HTMLVideoElement::VideoPresentationMode sourceVideoPresentationMode = toPresentationMode(fullscreenMode());
494
494
495
            if (targetVideoPresentationMode != HTMLVideoElement::VideoPresentationMode::PictureInPicture && sourceVideoPresentationMode == HTMLVideoElement::VideoPresentationMode::PictureInPicture)
495
            if (targetVideoPresentationMode != HTMLVideoElement::VideoPresentationMode::PictureInPicture && sourceVideoPresentationMode == HTMLVideoElement::VideoPresentationMode::PictureInPicture) {
496
                m_pictureInPictureObserver->didExitPictureInPicture();
496
                m_pictureInPictureObserver->didExitPictureInPicture();
497
                m_isFullscreen = false;
498
            }
497
        }
499
        }
498
#endif
500
#endif
499
    }
501
    }
Lines 507-512 void HTMLVideoElement::fullscreenModeChanged(VideoFullscreenMode mode) a/Source/WebCore/html/HTMLVideoElement.cpp_sec2
507
#if ENABLE(PICTURE_IN_PICTURE_API)
509
#if ENABLE(PICTURE_IN_PICTURE_API)
508
void HTMLVideoElement::didBecomeFullscreenElement()
510
void HTMLVideoElement::didBecomeFullscreenElement()
509
{
511
{
512
    m_isFullscreen = true;
510
    m_waitingForPictureInPictureWindowFrame = true;
513
    m_waitingForPictureInPictureWindowFrame = true;
511
    HTMLMediaElement::didBecomeFullscreenElement();
514
    HTMLMediaElement::didBecomeFullscreenElement();
512
}
515
}
Lines 515-521 void HTMLVideoElement::setPictureInPictureObserver(PictureInPictureObserver* obs a/Source/WebCore/html/HTMLVideoElement.cpp_sec3
515
{
518
{
516
    m_pictureInPictureObserver = observer;
519
    m_pictureInPictureObserver = observer;
517
}
520
}
518
519
#endif
521
#endif
520
522
521
#endif
523
#endif
Lines 526-531 void HTMLVideoElement::setVideoFullscreenFrame(FloatRect frame) a/Source/WebCore/html/HTMLVideoElement.cpp_sec4
526
    HTMLMediaElement::setVideoFullscreenFrame(frame);
528
    HTMLMediaElement::setVideoFullscreenFrame(frame);
527
529
528
#if ENABLE(PICTURE_IN_PICTURE_API)
530
#if ENABLE(PICTURE_IN_PICTURE_API)
531
    // fullscreenMode() does not always provide the correct fullscreen mode
532
    // when mode changing is happening (webkit.org/b/203443)
533
    if (!m_isFullscreen)
534
        return;
535
529
    if (toPresentationMode(fullscreenMode()) != VideoPresentationMode::PictureInPicture)
536
    if (toPresentationMode(fullscreenMode()) != VideoPresentationMode::PictureInPicture)
530
        return;
537
        return;
531
538
- a/Source/WebCore/html/HTMLVideoElement.h +1 lines
Lines 137-142 private: a/Source/WebCore/html/HTMLVideoElement.h_sec1
137
137
138
#if ENABLE(PICTURE_IN_PICTURE_API)
138
#if ENABLE(PICTURE_IN_PICTURE_API)
139
    bool m_waitingForPictureInPictureWindowFrame { false };
139
    bool m_waitingForPictureInPictureWindowFrame { false };
140
    bool m_isFullscreen { false };
140
    PictureInPictureObserver* m_pictureInPictureObserver { nullptr };
141
    PictureInPictureObserver* m_pictureInPictureObserver { nullptr };
141
#endif
142
#endif
142
};
143
};
- a/Source/WebCore/platform/PictureInPictureObserver.h -2 / +2 lines
Lines 32-40 namespace WebCore { a/Source/WebCore/platform/PictureInPictureObserver.h_sec1
32
class PictureInPictureObserver : public CanMakeWeakPtr<PictureInPictureObserver> {
32
class PictureInPictureObserver : public CanMakeWeakPtr<PictureInPictureObserver> {
33
public:
33
public:
34
    virtual ~PictureInPictureObserver() { };
34
    virtual ~PictureInPictureObserver() { };
35
    virtual void didEnterPictureInPicture(IntSize) = 0;
35
    virtual void didEnterPictureInPicture(const IntSize&) = 0;
36
    virtual void didExitPictureInPicture() = 0;
36
    virtual void didExitPictureInPicture() = 0;
37
    virtual void pictureInPictureWindowResized(IntSize) = 0;
37
    virtual void pictureInPictureWindowResized(const IntSize&) = 0;
38
};
38
};
39
39
40
}
40
}

Return to Bug 202615