PiP from Element Fullscreen should match AVKit's behavior
[WebKit-https.git] / Source / WebCore / platform / mac / VideoFullscreenInterfaceMac.mm
1 /*
2  * Copyright (C) 2016 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "VideoFullscreenInterfaceMac.h"
28
29 #if PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE)
30
31 #import "IntRect.h"
32 #import "Logging.h"
33 #import "PlaybackSessionInterfaceMac.h"
34 #import "TimeRanges.h"
35 #import "VideoFullscreenChangeObserver.h"
36 #import "VideoFullscreenModel.h"
37 #import "WebPlaybackControlsManager.h"
38 #import <AVFoundation/AVTime.h>
39 #import <pal/avfoundation/MediaTimeAVFoundation.h>
40 #import <pal/spi/cocoa/AVKitSPI.h>
41 #import <pal/spi/mac/PIPSPI.h>
42
43 #import <pal/cf/CoreMediaSoftLink.h>
44
45 SOFTLINK_AVKIT_FRAMEWORK()
46 SOFT_LINK_CLASS_OPTIONAL(AVKit, AVValueTiming)
47
48 SOFT_LINK_PRIVATE_FRAMEWORK_OPTIONAL(PIP)
49 SOFT_LINK_CLASS_OPTIONAL(PIP, PIPViewController)
50
51 @class WebVideoViewContainer;
52
53 @protocol WebVideoViewContainerDelegate <NSObject>
54
55 - (void)boundsDidChangeForVideoViewContainer:(WebVideoViewContainer *)videoViewContainer;
56 - (void)superviewDidChangeForVideoViewContainer:(WebVideoViewContainer *)videoViewContainer;
57
58 @end
59
60 using WebCore::VideoFullscreenModel;
61 using WebCore::HTMLMediaElementEnums;
62 using WebCore::VideoFullscreenInterfaceMac;
63 using WebCore::VideoFullscreenChangeObserver;
64 using WebCore::PlaybackSessionModel;
65
66 @interface WebVideoViewContainer : NSView {
67     id <WebVideoViewContainerDelegate> _videoViewContainerDelegate;
68 }
69
70 @property (nonatomic, assign) id <WebVideoViewContainerDelegate> videoViewContainerDelegate;
71
72 @end
73
74 @implementation WebVideoViewContainer
75
76 @synthesize videoViewContainerDelegate=_videoViewContainerDelegate;
77
78 - (void)resizeWithOldSuperviewSize:(NSSize)oldBoundsSize
79 {
80     [super resizeWithOldSuperviewSize:oldBoundsSize];
81
82     [_videoViewContainerDelegate boundsDidChangeForVideoViewContainer:self];
83 }
84
85 - (void)viewDidMoveToSuperview
86 {
87     [super viewDidMoveToSuperview];
88
89     [_videoViewContainerDelegate superviewDidChangeForVideoViewContainer:self];
90 }
91
92 @end
93
94 enum class PIPState {
95     NotInPIP,
96     InPIP,
97     ExitingPIP
98 };
99
100 @interface WebVideoFullscreenInterfaceMacObjC : NSObject <PIPViewControllerDelegate, WebVideoViewContainerDelegate> {
101     WebCore::VideoFullscreenInterfaceMac* _videoFullscreenInterfaceMac;
102     NSSize _videoDimensions;
103     RetainPtr<PIPViewController> _pipViewController;
104     RetainPtr<NSViewController> _videoViewContainerController;
105     RetainPtr<WebVideoViewContainer> _videoViewContainer;
106     PIPState _pipState;
107     RetainPtr<NSWindow> _returningWindow;
108     NSRect _returningRect;
109     BOOL _playing;
110     BOOL _exitingToStandardFullscreen;
111 }
112
113 - (instancetype)initWithVideoFullscreenInterfaceMac:(WebCore::VideoFullscreenInterfaceMac*)videoFullscreenInterfaceMac;
114 - (void)invalidateFullscreenState;
115 - (void)invalidate;
116
117 // Tracking video playback state
118 @property (nonatomic) NSSize videoDimensions;
119 @property (nonatomic, getter=isPlaying) BOOL playing;
120 - (void)updateIsPlaying:(BOOL)isPlaying newPlaybackRate:(float)playbackRate;
121
122 // Handling PIP transitions
123 @property (nonatomic, getter=isExitingToStandardFullscreen) BOOL exitingToStandardFullscreen;
124
125 - (void)setUpPIPForVideoView:(NSView *)videoView withFrame:(NSRect)frame inWindow:(NSWindow *)window;
126 - (void)enterPIP;
127 - (void)exitPIP;
128 - (void)exitPIPAnimatingToRect:(NSRect)rect inWindow:(NSWindow *)window;
129
130 @end
131
132 @implementation WebVideoFullscreenInterfaceMacObjC
133
134 @synthesize playing=_playing;
135 @synthesize videoDimensions=_videoDimensions;
136 @synthesize exitingToStandardFullscreen=_exitingToStandardFullscreen;
137
138 - (instancetype)initWithVideoFullscreenInterfaceMac:(WebCore::VideoFullscreenInterfaceMac*)videoFullscreenInterfaceMac
139 {
140     if (!(self = [super init]))
141         return nil;
142
143     _videoFullscreenInterfaceMac = videoFullscreenInterfaceMac;
144     _pipState = PIPState::NotInPIP;
145
146     return self;
147 }
148
149 - (void)invalidateFullscreenState
150 {
151     [_pipViewController setDelegate:nil];
152     _pipViewController = nil;
153     [_videoViewContainer removeFromSuperview];
154     [_videoViewContainer setVideoViewContainerDelegate:nil];
155     _videoViewContainer = nil;
156     _videoViewContainerController = nil;
157     _pipState = PIPState::NotInPIP;
158     _exitingToStandardFullscreen = NO;
159     _returningWindow = nil;
160     _returningRect = NSZeroRect;
161 }
162
163 - (void)invalidate
164 {
165     [self invalidateFullscreenState];
166     _videoFullscreenInterfaceMac = nullptr;
167     _videoDimensions = NSZeroSize;
168 }
169
170 - (void)updateIsPlaying:(BOOL)isPlaying newPlaybackRate:(float)playbackRate
171 {
172     _playing = isPlaying && playbackRate;
173
174     [_pipViewController setPlaying:_playing];
175 }
176
177 - (void)setVideoDimensions:(NSSize)videoDimensions
178 {
179     _videoDimensions = videoDimensions;
180
181     [_pipViewController setAspectRatio:_videoDimensions];
182 }
183
184 - (void)setUpPIPForVideoView:(NSView *)videoView withFrame:(NSRect)frame inWindow:(NSWindow *)window
185 {
186     ASSERT(!_pipViewController);
187     ASSERT(!_videoViewContainerController);
188     ASSERT(!_videoViewContainer);
189
190     _pipViewController = adoptNS([allocPIPViewControllerInstance() init]);
191     [_pipViewController setDelegate:self];
192     [_pipViewController setUserCanResize:YES];
193     [_pipViewController setPlaying:_playing];
194     [self setVideoDimensions:NSEqualSizes(_videoDimensions, NSZeroSize) ? frame.size : _videoDimensions];
195     if (_videoFullscreenInterfaceMac && _videoFullscreenInterfaceMac->videoFullscreenModel())
196         _videoFullscreenInterfaceMac->videoFullscreenModel()->setVideoLayerGravity(VideoFullscreenModel::VideoGravityResizeAspectFill);
197
198     _videoViewContainer = adoptNS([[WebVideoViewContainer alloc] initWithFrame:frame]);
199     [_videoViewContainer setVideoViewContainerDelegate:self];
200     [_videoViewContainer addSubview:videoView];
201     videoView.frame = [_videoViewContainer bounds];
202     videoView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
203
204     _videoViewContainerController = adoptNS([[NSViewController alloc] init]);
205     [_videoViewContainerController setView:_videoViewContainer.get()];
206     [window.contentView addSubview:_videoViewContainer.get() positioned:NSWindowAbove relativeTo:nil];
207 }
208
209 - (void)enterPIP
210 {
211     if (_pipState == PIPState::InPIP)
212         return;
213
214     [_videoViewContainerController view].layer.backgroundColor = CGColorGetConstantColor(kCGColorBlack);
215     [_pipViewController presentViewControllerAsPictureInPicture:_videoViewContainerController.get()];
216     _pipState = PIPState::InPIP;
217 }
218
219 - (void)exitPIP
220 {
221     if (_pipState != PIPState::InPIP || !_pipViewController || !_videoViewContainerController)
222         return;
223
224     [_videoViewContainerController view].layer.backgroundColor = CGColorGetConstantColor(kCGColorClear);
225     [_pipViewController dismissViewController:_videoViewContainerController.get()];
226     _pipState = PIPState::ExitingPIP;
227 }
228
229 - (void)exitPIPAnimatingToRect:(NSRect)rect inWindow:(NSWindow *)window
230 {
231     _returningWindow = window;
232     _returningRect = rect;
233
234     [_pipViewController setReplacementRect:rect];
235     [_pipViewController setReplacementWindow:window];
236
237     [self exitPIP];
238 }
239
240 // WebVideoViewContainerDelegate
241
242 - (void)boundsDidChangeForVideoViewContainer:(WebVideoViewContainer *)videoViewContainer
243 {
244     if (!_videoViewContainer || !_pipViewController)
245         return;
246
247     ASSERT_UNUSED(videoViewContainer, videoViewContainer == _videoViewContainer);
248
249     if (_videoFullscreenInterfaceMac && _videoFullscreenInterfaceMac->videoFullscreenModel())
250         _videoFullscreenInterfaceMac->videoFullscreenModel()->setVideoLayerFrame([_videoViewContainer bounds]);
251 }
252
253 - (void)superviewDidChangeForVideoViewContainer:(WebVideoViewContainer *)videoViewContainer
254 {
255     if (!_videoViewContainer || !_pipViewController)
256         return;
257
258     ASSERT(videoViewContainer == _videoViewContainer);
259
260     if (![videoViewContainer isDescendantOf:[_pipViewController view]])
261         return;
262
263     // Once the view is moved into the pip view, make sure it resizes with the pip view.
264     videoViewContainer.frame = [videoViewContainer superview].bounds;
265     videoViewContainer.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
266 }
267
268 // PIPViewControllerDelegate
269
270 - (BOOL)pipShouldClose:(PIPViewController *)pip
271 {
272     ASSERT_UNUSED(pip, pip == _pipViewController);
273
274     if (!_videoFullscreenInterfaceMac || !_videoFullscreenInterfaceMac->videoFullscreenChangeObserver())
275         return YES;
276
277     _videoFullscreenInterfaceMac->requestHideAndExitFullscreen();
278
279     return NO;
280 }
281
282 - (void)pipDidClose:(PIPViewController *)pip
283 {
284     ASSERT_UNUSED(pip, pip == _pipViewController);
285
286     if (_videoFullscreenInterfaceMac && _videoFullscreenInterfaceMac->videoFullscreenModel() && _videoViewContainer && _returningWindow && !NSEqualRects(_returningRect, NSZeroRect)) {
287         [NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
288             context.allowsImplicitAnimation = NO;
289             [_videoViewContainer setFrame:_returningRect];
290             _videoFullscreenInterfaceMac->videoFullscreenModel()->setVideoLayerFrame([_videoViewContainer bounds]);
291             _videoFullscreenInterfaceMac->videoFullscreenModel()->setVideoLayerGravity(VideoFullscreenModel::VideoGravityResizeAspect);
292
293             [[_returningWindow contentView] addSubview:_videoViewContainer.get() positioned:NSWindowAbove relativeTo:nil];
294         } completionHandler:nil];
295     }
296
297     if (_videoFullscreenInterfaceMac) {
298         if (!self.isExitingToStandardFullscreen) {
299             if (VideoFullscreenModel* videoFullscreenModel = _videoFullscreenInterfaceMac->videoFullscreenModel()) {
300                 videoFullscreenModel->didExitPictureInPicture();
301                 videoFullscreenModel->setVideoLayerGravity(VideoFullscreenModel::VideoGravityResizeAspect);
302             }
303         }
304
305         if (VideoFullscreenChangeObserver* fullscreenChangeObserver = _videoFullscreenInterfaceMac->videoFullscreenChangeObserver())
306             fullscreenChangeObserver->didExitFullscreen();
307     }
308 }
309
310 - (void)pipActionPlay:(PIPViewController *)pip
311 {
312     ASSERT_UNUSED(pip, pip == _pipViewController);
313
314     if (_videoFullscreenInterfaceMac && _videoFullscreenInterfaceMac->playbackSessionModel())
315         _videoFullscreenInterfaceMac->playbackSessionModel()->play();
316 }
317
318 - (void)pipActionPause:(PIPViewController *)pip
319 {
320     ASSERT_UNUSED(pip, pip == _pipViewController);
321
322     if (_videoFullscreenInterfaceMac && _videoFullscreenInterfaceMac->playbackSessionModel())
323         _videoFullscreenInterfaceMac->playbackSessionModel()->pause();
324 }
325
326 - (void)pipActionStop:(PIPViewController *)pip
327 {
328     ASSERT_UNUSED(pip, pip == _pipViewController);
329
330     if (!_videoFullscreenInterfaceMac)
331         return;
332
333     if (PlaybackSessionModel* playbackSessionModel = _videoFullscreenInterfaceMac->playbackSessionModel())
334         playbackSessionModel->pause();
335
336     // FIXME 25096170: Should animate only if the page with the video is unobscured. For now, always close without animation.
337     [self exitPIP];
338 }
339
340 @end
341
342 namespace WebCore {
343 using namespace PAL;
344
345 VideoFullscreenInterfaceMac::VideoFullscreenInterfaceMac(PlaybackSessionInterfaceMac& playbackSessionInterface)
346     : m_playbackSessionInterface(playbackSessionInterface)
347 {
348     ASSERT(m_playbackSessionInterface->playbackSessionModel());
349     auto model = m_playbackSessionInterface->playbackSessionModel();
350     model->addClient(*this);
351     [videoFullscreenInterfaceObjC() updateIsPlaying:model->isPlaying() newPlaybackRate:model->playbackRate()];
352 }
353
354 VideoFullscreenInterfaceMac::~VideoFullscreenInterfaceMac()
355 {
356     if (m_playbackSessionInterface->playbackSessionModel())
357         m_playbackSessionInterface->playbackSessionModel()->removeClient(*this);
358     if (m_videoFullscreenModel)
359         m_videoFullscreenModel->removeClient(*this);
360 }
361
362 void VideoFullscreenInterfaceMac::setVideoFullscreenModel(VideoFullscreenModel* model)
363 {
364     if (m_videoFullscreenModel)
365         m_videoFullscreenModel->removeClient(*this);
366     m_videoFullscreenModel = model;
367     if (m_videoFullscreenModel)
368         m_videoFullscreenModel->addClient(*this);
369 }
370
371 void VideoFullscreenInterfaceMac::setVideoFullscreenChangeObserver(VideoFullscreenChangeObserver* observer)
372 {
373     m_fullscreenChangeObserver = observer;
374 }
375
376 void VideoFullscreenInterfaceMac::setMode(HTMLMediaElementEnums::VideoFullscreenMode mode)
377 {
378     HTMLMediaElementEnums::VideoFullscreenMode newMode = m_mode | mode;
379     if (m_mode == newMode)
380         return;
381
382     m_mode = newMode;
383     if (m_videoFullscreenModel)
384         m_videoFullscreenModel->fullscreenModeChanged(m_mode);
385 }
386
387 void VideoFullscreenInterfaceMac::clearMode(HTMLMediaElementEnums::VideoFullscreenMode mode)
388 {
389     HTMLMediaElementEnums::VideoFullscreenMode newMode = m_mode & ~mode;
390     if (m_mode == newMode)
391         return;
392
393     m_mode = newMode;
394     if (m_videoFullscreenModel)
395         m_videoFullscreenModel->fullscreenModeChanged(m_mode);
396 }
397
398 void VideoFullscreenInterfaceMac::rateChanged(bool isPlaying, float playbackRate)
399 {
400     [videoFullscreenInterfaceObjC() updateIsPlaying:isPlaying newPlaybackRate:playbackRate];
401 }
402
403 void VideoFullscreenInterfaceMac::ensureControlsManager()
404 {
405     m_playbackSessionInterface->ensureControlsManager();
406 }
407
408 WebVideoFullscreenInterfaceMacObjC *VideoFullscreenInterfaceMac::videoFullscreenInterfaceObjC()
409 {
410     if (!m_webVideoFullscreenInterfaceObjC)
411         m_webVideoFullscreenInterfaceObjC = adoptNS([[WebVideoFullscreenInterfaceMacObjC alloc] initWithVideoFullscreenInterfaceMac:this]);
412
413     return m_webVideoFullscreenInterfaceObjC.get();
414 }
415
416 void VideoFullscreenInterfaceMac::setupFullscreen(NSView& layerHostedView, const IntRect& initialRect, NSWindow *parentWindow, HTMLMediaElementEnums::VideoFullscreenMode mode, bool allowsPictureInPicturePlayback)
417 {
418     LOG(Fullscreen, "VideoFullscreenInterfaceMac::setupFullscreen(%p), initialRect:{%d, %d, %d, %d}, parentWindow:%p, mode:%d", this, initialRect.x(), initialRect.y(), initialRect.width(), initialRect.height(), parentWindow, mode);
419
420     UNUSED_PARAM(allowsPictureInPicturePlayback);
421     ASSERT(mode == HTMLMediaElementEnums::VideoFullscreenModePictureInPicture);
422
423     m_mode = mode;
424
425     [videoFullscreenInterfaceObjC() setUpPIPForVideoView:&layerHostedView withFrame:(NSRect)initialRect inWindow:parentWindow];
426
427     dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), this] {
428         if (m_fullscreenChangeObserver)
429             m_fullscreenChangeObserver->didSetupFullscreen();
430     });
431 }
432
433 void VideoFullscreenInterfaceMac::enterFullscreen()
434 {
435     LOG(Fullscreen, "VideoFullscreenInterfaceMac::enterFullscreen(%p)", this);
436
437     if (mode() == HTMLMediaElementEnums::VideoFullscreenModePictureInPicture) {
438         m_videoFullscreenModel->willEnterPictureInPicture();
439         [m_webVideoFullscreenInterfaceObjC enterPIP];
440
441 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
442         [m_playbackSessionInterface->playBackControlsManager() setPictureInPictureActive:YES];
443 #endif
444
445         // FIXME(rdar://problem/42250952): Move this call into a completion handler or delegate callback.
446         m_videoFullscreenModel->didEnterPictureInPicture();
447         if (m_fullscreenChangeObserver)
448             m_fullscreenChangeObserver->didEnterFullscreen();
449     }
450 }
451
452 void VideoFullscreenInterfaceMac::exitFullscreen(const IntRect& finalRect, NSWindow *parentWindow)
453 {
454     LOG(Fullscreen, "VideoFullscreenInterfaceMac::exitFullscreen(%p), finalRect:{%d, %d, %d, %d}, parentWindow:%p", this, finalRect.x(), finalRect.y(), finalRect.width(), finalRect.height(), parentWindow);
455
456 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
457     [m_playbackSessionInterface->playBackControlsManager() setPictureInPictureActive:NO];
458 #endif
459
460     if (finalRect.isEmpty())
461         [m_webVideoFullscreenInterfaceObjC exitPIP];
462     else
463         [m_webVideoFullscreenInterfaceObjC exitPIPAnimatingToRect:finalRect inWindow:parentWindow];
464 }
465
466 void VideoFullscreenInterfaceMac::exitFullscreenWithoutAnimationToMode(HTMLMediaElementEnums::VideoFullscreenMode mode)
467 {
468     LOG(Fullscreen, "VideoFullscreenInterfaceMac::exitFullscreenWithoutAnimationToMode(%p), mode:%d", this, mode);
469
470 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
471     [m_playbackSessionInterface->playBackControlsManager() setPictureInPictureActive:NO];
472 #endif
473
474     bool isExitingToStandardFullscreen = mode == HTMLMediaElementEnums::VideoFullscreenModeStandard;
475     // On Mac, standard fullscreen is handled by the Fullscreen API and not by VideoFullscreenManager.
476     // Just update m_mode directly to HTMLMediaElementEnums::VideoFullscreenModeStandard in that case to keep
477     // m_mode in sync with the fullscreen mode in HTMLMediaElement.
478     if (isExitingToStandardFullscreen)
479         m_mode = HTMLMediaElementEnums::VideoFullscreenModeStandard;
480
481     [m_webVideoFullscreenInterfaceObjC setExitingToStandardFullscreen:isExitingToStandardFullscreen];
482     [m_webVideoFullscreenInterfaceObjC exitPIP];
483 }
484
485 void VideoFullscreenInterfaceMac::cleanupFullscreen()
486 {
487     LOG(Fullscreen, "VideoFullscreenInterfaceMac::cleanupFullscreen(%p)", this);
488
489     [m_webVideoFullscreenInterfaceObjC exitPIP];
490     [m_webVideoFullscreenInterfaceObjC invalidateFullscreenState];
491
492     if (m_fullscreenChangeObserver)
493         m_fullscreenChangeObserver->didCleanupFullscreen();
494 }
495
496 void VideoFullscreenInterfaceMac::invalidate()
497 {
498     LOG(Fullscreen, "VideoFullscreenInterfaceMac::invalidate(%p)", this);
499
500     m_videoFullscreenModel = nil;
501     m_fullscreenChangeObserver = nil;
502
503     cleanupFullscreen();
504
505     [m_webVideoFullscreenInterfaceObjC invalidate];
506     m_webVideoFullscreenInterfaceObjC = nil;
507 }
508
509 void VideoFullscreenInterfaceMac::requestHideAndExitFullscreen()
510 {
511     if (!m_videoFullscreenModel)
512         return;
513
514     m_videoFullscreenModel->requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
515     m_videoFullscreenModel->willExitPictureInPicture();
516 }
517
518 #if !LOG_DISABLED
519 static const char* boolString(bool val)
520 {
521     return val ? "true" : "false";
522 }
523 #endif
524
525 void VideoFullscreenInterfaceMac::preparedToReturnToInline(bool visible, const IntRect& inlineRect, NSWindow *parentWindow)
526 {
527     LOG(Fullscreen, "VideoFullscreenInterfaceMac::preparedToReturnToInline(%p), visible:%s, inlineRect:{%d, %d, %d, %d}, parentWindow:%p", this, boolString(visible), inlineRect.x(), inlineRect.y(), inlineRect.width(), inlineRect.height(), parentWindow);
528
529     if (!visible) {
530         [m_webVideoFullscreenInterfaceObjC exitPIP];
531         return;
532     }
533
534     ASSERT(parentWindow);
535     [m_webVideoFullscreenInterfaceObjC exitPIPAnimatingToRect:(NSRect)inlineRect inWindow:parentWindow];
536 }
537
538 void VideoFullscreenInterfaceMac::externalPlaybackChanged(bool enabled, PlaybackSessionModel::ExternalPlaybackTargetType, const String&)
539 {
540     LOG(Fullscreen, "VideoFullscreenInterfaceMac::externalPlaybackChanged(%p), enabled:%s", this, boolString(enabled));
541
542     if (enabled && m_mode == HTMLMediaElementEnums::VideoFullscreenModePictureInPicture)
543         exitFullscreen(IntRect(), nil);
544 }
545
546 void VideoFullscreenInterfaceMac::hasVideoChanged(bool hasVideo)
547 {
548     LOG(Fullscreen, "VideoFullscreenInterfaceMac::hasVideoChanged(%p):%s", this, boolString(hasVideo));
549
550     if (!hasVideo)
551         exitFullscreenWithoutAnimationToMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
552 }
553
554 void VideoFullscreenInterfaceMac::videoDimensionsChanged(const FloatSize& videoDimensions)
555 {
556     LOG(Fullscreen, "VideoFullscreenInterfaceMac::videoDimensionsChanged(%p), width:%.0f, height:%.0f", this, videoDimensions.width(), videoDimensions.height());
557
558     // Width and height can be zero when we are transitioning from one video to another. Ignore zero values.
559     if (!videoDimensions.isZero())
560         [m_webVideoFullscreenInterfaceObjC setVideoDimensions:videoDimensions];
561 }
562
563 bool VideoFullscreenInterfaceMac::isPlayingVideoInEnhancedFullscreen() const
564 {
565     return hasMode(WebCore::HTMLMediaElementEnums::VideoFullscreenModePictureInPicture) && [m_webVideoFullscreenInterfaceObjC isPlaying];
566 }
567
568 bool supportsPictureInPicture()
569 {
570     return PIPLibrary() && getPIPViewControllerClass();
571 }
572
573 }
574
575 #endif