bf676f7538ade23251f52caa4ad1bb03208c94ab
[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         _videoFullscreenInterfaceMac->clearMode(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture);
306
307         if (VideoFullscreenChangeObserver* fullscreenChangeObserver = _videoFullscreenInterfaceMac->videoFullscreenChangeObserver())
308             fullscreenChangeObserver->didExitFullscreen();
309     }
310 }
311
312 - (void)pipActionPlay:(PIPViewController *)pip
313 {
314     ASSERT_UNUSED(pip, pip == _pipViewController);
315
316     if (_videoFullscreenInterfaceMac && _videoFullscreenInterfaceMac->playbackSessionModel())
317         _videoFullscreenInterfaceMac->playbackSessionModel()->play();
318 }
319
320 - (void)pipActionPause:(PIPViewController *)pip
321 {
322     ASSERT_UNUSED(pip, pip == _pipViewController);
323
324     if (_videoFullscreenInterfaceMac && _videoFullscreenInterfaceMac->playbackSessionModel())
325         _videoFullscreenInterfaceMac->playbackSessionModel()->pause();
326 }
327
328 - (void)pipActionStop:(PIPViewController *)pip
329 {
330     ASSERT_UNUSED(pip, pip == _pipViewController);
331
332     if (!_videoFullscreenInterfaceMac)
333         return;
334
335     if (PlaybackSessionModel* playbackSessionModel = _videoFullscreenInterfaceMac->playbackSessionModel())
336         playbackSessionModel->pause();
337
338     // FIXME 25096170: Should animate only if the page with the video is unobscured. For now, always close without animation.
339     [self exitPIP];
340 }
341
342 @end
343
344 namespace WebCore {
345 using namespace PAL;
346
347 VideoFullscreenInterfaceMac::VideoFullscreenInterfaceMac(PlaybackSessionInterfaceMac& playbackSessionInterface)
348     : m_playbackSessionInterface(playbackSessionInterface)
349 {
350     ASSERT(m_playbackSessionInterface->playbackSessionModel());
351     auto model = m_playbackSessionInterface->playbackSessionModel();
352     model->addClient(*this);
353     [videoFullscreenInterfaceObjC() updateIsPlaying:model->isPlaying() newPlaybackRate:model->playbackRate()];
354 }
355
356 VideoFullscreenInterfaceMac::~VideoFullscreenInterfaceMac()
357 {
358     if (m_playbackSessionInterface->playbackSessionModel())
359         m_playbackSessionInterface->playbackSessionModel()->removeClient(*this);
360     if (m_videoFullscreenModel)
361         m_videoFullscreenModel->removeClient(*this);
362 }
363
364 void VideoFullscreenInterfaceMac::setVideoFullscreenModel(VideoFullscreenModel* model)
365 {
366     if (m_videoFullscreenModel)
367         m_videoFullscreenModel->removeClient(*this);
368     m_videoFullscreenModel = model;
369     if (m_videoFullscreenModel)
370         m_videoFullscreenModel->addClient(*this);
371 }
372
373 void VideoFullscreenInterfaceMac::setVideoFullscreenChangeObserver(VideoFullscreenChangeObserver* observer)
374 {
375     m_fullscreenChangeObserver = observer;
376 }
377
378 void VideoFullscreenInterfaceMac::setMode(HTMLMediaElementEnums::VideoFullscreenMode mode)
379 {
380     HTMLMediaElementEnums::VideoFullscreenMode newMode = m_mode | mode;
381     if (m_mode == newMode)
382         return;
383
384     m_mode = newMode;
385     if (m_videoFullscreenModel)
386         m_videoFullscreenModel->fullscreenModeChanged(m_mode);
387 }
388
389 void VideoFullscreenInterfaceMac::clearMode(HTMLMediaElementEnums::VideoFullscreenMode mode)
390 {
391     HTMLMediaElementEnums::VideoFullscreenMode newMode = m_mode & ~mode;
392     if (m_mode == newMode)
393         return;
394
395     m_mode = newMode;
396     if (m_videoFullscreenModel)
397         m_videoFullscreenModel->fullscreenModeChanged(m_mode);
398 }
399
400 void VideoFullscreenInterfaceMac::rateChanged(bool isPlaying, float playbackRate)
401 {
402     [videoFullscreenInterfaceObjC() updateIsPlaying:isPlaying newPlaybackRate:playbackRate];
403 }
404
405 void VideoFullscreenInterfaceMac::ensureControlsManager()
406 {
407     m_playbackSessionInterface->ensureControlsManager();
408 }
409
410 WebVideoFullscreenInterfaceMacObjC *VideoFullscreenInterfaceMac::videoFullscreenInterfaceObjC()
411 {
412     if (!m_webVideoFullscreenInterfaceObjC)
413         m_webVideoFullscreenInterfaceObjC = adoptNS([[WebVideoFullscreenInterfaceMacObjC alloc] initWithVideoFullscreenInterfaceMac:this]);
414
415     return m_webVideoFullscreenInterfaceObjC.get();
416 }
417
418 void VideoFullscreenInterfaceMac::setupFullscreen(NSView& layerHostedView, const IntRect& initialRect, NSWindow *parentWindow, HTMLMediaElementEnums::VideoFullscreenMode mode, bool allowsPictureInPicturePlayback)
419 {
420     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);
421
422     UNUSED_PARAM(allowsPictureInPicturePlayback);
423     ASSERT(mode == HTMLMediaElementEnums::VideoFullscreenModePictureInPicture);
424
425     m_mode = mode;
426
427     [videoFullscreenInterfaceObjC() setUpPIPForVideoView:&layerHostedView withFrame:(NSRect)initialRect inWindow:parentWindow];
428
429     dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), this] {
430         if (m_fullscreenChangeObserver)
431             m_fullscreenChangeObserver->didSetupFullscreen();
432     });
433 }
434
435 void VideoFullscreenInterfaceMac::enterFullscreen()
436 {
437     LOG(Fullscreen, "VideoFullscreenInterfaceMac::enterFullscreen(%p)", this);
438
439     if (mode() == HTMLMediaElementEnums::VideoFullscreenModePictureInPicture) {
440         m_videoFullscreenModel->willEnterPictureInPicture();
441         [m_webVideoFullscreenInterfaceObjC enterPIP];
442
443 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
444         [m_playbackSessionInterface->playBackControlsManager() setPictureInPictureActive:YES];
445 #endif
446
447         // FIXME(rdar://problem/42250952): Move this call into a completion handler or delegate callback.
448         m_videoFullscreenModel->didEnterPictureInPicture();
449         if (m_fullscreenChangeObserver)
450             m_fullscreenChangeObserver->didEnterFullscreen();
451     }
452 }
453
454 void VideoFullscreenInterfaceMac::exitFullscreen(const IntRect& finalRect, NSWindow *parentWindow)
455 {
456     LOG(Fullscreen, "VideoFullscreenInterfaceMac::exitFullscreen(%p), finalRect:{%d, %d, %d, %d}, parentWindow:%p", this, finalRect.x(), finalRect.y(), finalRect.width(), finalRect.height(), parentWindow);
457
458 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
459     [m_playbackSessionInterface->playBackControlsManager() setPictureInPictureActive:NO];
460 #endif
461
462     if (finalRect.isEmpty())
463         [m_webVideoFullscreenInterfaceObjC exitPIP];
464     else
465         [m_webVideoFullscreenInterfaceObjC exitPIPAnimatingToRect:finalRect inWindow:parentWindow];
466 }
467
468 void VideoFullscreenInterfaceMac::exitFullscreenWithoutAnimationToMode(HTMLMediaElementEnums::VideoFullscreenMode mode)
469 {
470     LOG(Fullscreen, "VideoFullscreenInterfaceMac::exitFullscreenWithoutAnimationToMode(%p), mode:%d", this, mode);
471
472 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
473     [m_playbackSessionInterface->playBackControlsManager() setPictureInPictureActive:NO];
474 #endif
475
476     bool isExitingToStandardFullscreen = mode == HTMLMediaElementEnums::VideoFullscreenModeStandard;
477     // On Mac, standard fullscreen is handled by the Fullscreen API and not by VideoFullscreenManager.
478     // Just update m_mode directly to HTMLMediaElementEnums::VideoFullscreenModeStandard in that case to keep
479     // m_mode in sync with the fullscreen mode in HTMLMediaElement.
480     if (isExitingToStandardFullscreen)
481         m_mode = HTMLMediaElementEnums::VideoFullscreenModeStandard;
482
483     [m_webVideoFullscreenInterfaceObjC setExitingToStandardFullscreen:isExitingToStandardFullscreen];
484     [m_webVideoFullscreenInterfaceObjC exitPIP];
485 }
486
487 void VideoFullscreenInterfaceMac::cleanupFullscreen()
488 {
489     LOG(Fullscreen, "VideoFullscreenInterfaceMac::cleanupFullscreen(%p)", this);
490
491     [m_webVideoFullscreenInterfaceObjC exitPIP];
492     [m_webVideoFullscreenInterfaceObjC invalidateFullscreenState];
493
494     if (m_fullscreenChangeObserver)
495         m_fullscreenChangeObserver->didCleanupFullscreen();
496 }
497
498 void VideoFullscreenInterfaceMac::invalidate()
499 {
500     LOG(Fullscreen, "VideoFullscreenInterfaceMac::invalidate(%p)", this);
501
502     m_videoFullscreenModel = nil;
503     m_fullscreenChangeObserver = nil;
504
505     cleanupFullscreen();
506
507     [m_webVideoFullscreenInterfaceObjC invalidate];
508     m_webVideoFullscreenInterfaceObjC = nil;
509 }
510
511 void VideoFullscreenInterfaceMac::requestHideAndExitFullscreen()
512 {
513     if (!m_videoFullscreenModel)
514         return;
515
516     m_videoFullscreenModel->requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
517     m_videoFullscreenModel->willExitPictureInPicture();
518 }
519
520 #if !LOG_DISABLED
521 static const char* boolString(bool val)
522 {
523     return val ? "true" : "false";
524 }
525 #endif
526
527 void VideoFullscreenInterfaceMac::preparedToReturnToInline(bool visible, const IntRect& inlineRect, NSWindow *parentWindow)
528 {
529     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);
530
531     if (!visible) {
532         [m_webVideoFullscreenInterfaceObjC exitPIP];
533         return;
534     }
535
536     ASSERT(parentWindow);
537     [m_webVideoFullscreenInterfaceObjC exitPIPAnimatingToRect:(NSRect)inlineRect inWindow:parentWindow];
538 }
539
540 void VideoFullscreenInterfaceMac::externalPlaybackChanged(bool enabled, PlaybackSessionModel::ExternalPlaybackTargetType, const String&)
541 {
542     LOG(Fullscreen, "VideoFullscreenInterfaceMac::externalPlaybackChanged(%p), enabled:%s", this, boolString(enabled));
543
544     if (enabled && m_mode == HTMLMediaElementEnums::VideoFullscreenModePictureInPicture)
545         exitFullscreen(IntRect(), nil);
546 }
547
548 void VideoFullscreenInterfaceMac::hasVideoChanged(bool hasVideo)
549 {
550     LOG(Fullscreen, "VideoFullscreenInterfaceMac::hasVideoChanged(%p):%s", this, boolString(hasVideo));
551
552     if (!hasVideo)
553         exitFullscreenWithoutAnimationToMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
554 }
555
556 void VideoFullscreenInterfaceMac::videoDimensionsChanged(const FloatSize& videoDimensions)
557 {
558     LOG(Fullscreen, "VideoFullscreenInterfaceMac::videoDimensionsChanged(%p), width:%.0f, height:%.0f", this, videoDimensions.width(), videoDimensions.height());
559
560     // Width and height can be zero when we are transitioning from one video to another. Ignore zero values.
561     if (!videoDimensions.isZero())
562         [m_webVideoFullscreenInterfaceObjC setVideoDimensions:videoDimensions];
563 }
564
565 bool VideoFullscreenInterfaceMac::isPlayingVideoInEnhancedFullscreen() const
566 {
567     return hasMode(WebCore::HTMLMediaElementEnums::VideoFullscreenModePictureInPicture) && [m_webVideoFullscreenInterfaceObjC isPlaying];
568 }
569
570 bool supportsPictureInPicture()
571 {
572     return PIPLibrary() && getPIPViewControllerClass();
573 }
574
575 }
576
577 #endif