[FreeType] Incorrect application of glyph positioning in the Y direction
[WebKit-https.git] / Source / WebCore / platform / mac / VideoFullscreenInterfaceMac.mm
1 /*
2  * Copyright (C) 2016-2019 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::MediaPlayerEnums;
63 using WebCore::VideoFullscreenInterfaceMac;
64 using WebCore::VideoFullscreenChangeObserver;
65 using WebCore::PlaybackSessionModel;
66
67 @interface WebVideoViewContainer : NSView {
68     __unsafe_unretained id <WebVideoViewContainerDelegate> _videoViewContainerDelegate;
69 }
70
71 @property (nonatomic, assign) id <WebVideoViewContainerDelegate> videoViewContainerDelegate;
72
73 @end
74
75 @implementation WebVideoViewContainer
76
77 @synthesize videoViewContainerDelegate=_videoViewContainerDelegate;
78
79 - (void)resizeWithOldSuperviewSize:(NSSize)oldBoundsSize
80 {
81     [super resizeWithOldSuperviewSize:oldBoundsSize];
82
83     [_videoViewContainerDelegate boundsDidChangeForVideoViewContainer:self];
84 }
85
86 - (void)viewDidMoveToSuperview
87 {
88     [super viewDidMoveToSuperview];
89
90     [_videoViewContainerDelegate superviewDidChangeForVideoViewContainer:self];
91 }
92
93 @end
94
95 enum class PIPState {
96     NotInPIP,
97     InPIP,
98     ExitingPIP
99 };
100
101 @interface WebVideoFullscreenInterfaceMacObjC : NSObject <PIPViewControllerDelegate, WebVideoViewContainerDelegate> {
102     WebCore::VideoFullscreenInterfaceMac* _videoFullscreenInterfaceMac;
103     NSSize _videoDimensions;
104     RetainPtr<PIPViewController> _pipViewController;
105     RetainPtr<NSViewController> _videoViewContainerController;
106     RetainPtr<WebVideoViewContainer> _videoViewContainer;
107     PIPState _pipState;
108     RetainPtr<NSWindow> _returningWindow;
109     NSRect _returningRect;
110     BOOL _playing;
111     BOOL _exitingToStandardFullscreen;
112 }
113
114 - (instancetype)initWithVideoFullscreenInterfaceMac:(WebCore::VideoFullscreenInterfaceMac*)videoFullscreenInterfaceMac;
115 - (void)invalidateFullscreenState;
116 - (void)invalidate;
117
118 // Tracking video playback state
119 @property (nonatomic) NSSize videoDimensions;
120 @property (nonatomic, getter=isPlaying) BOOL playing;
121 - (void)updateIsPlaying:(BOOL)isPlaying newPlaybackRate:(float)playbackRate;
122
123 // Handling PIP transitions
124 @property (nonatomic, getter=isExitingToStandardFullscreen) BOOL exitingToStandardFullscreen;
125
126 - (void)setUpPIPForVideoView:(NSView *)videoView withFrame:(NSRect)frame inWindow:(NSWindow *)window;
127 - (void)enterPIP;
128 - (void)exitPIP;
129 - (void)exitPIPAnimatingToRect:(NSRect)rect inWindow:(NSWindow *)window;
130
131 @end
132
133 @implementation WebVideoFullscreenInterfaceMacObjC
134
135 @synthesize playing=_playing;
136 @synthesize videoDimensions=_videoDimensions;
137 @synthesize exitingToStandardFullscreen=_exitingToStandardFullscreen;
138
139 - (instancetype)initWithVideoFullscreenInterfaceMac:(WebCore::VideoFullscreenInterfaceMac*)videoFullscreenInterfaceMac
140 {
141     if (!(self = [super init]))
142         return nil;
143
144     _videoFullscreenInterfaceMac = videoFullscreenInterfaceMac;
145     _pipState = PIPState::NotInPIP;
146
147     return self;
148 }
149
150 - (void)invalidateFullscreenState
151 {
152     [_pipViewController setDelegate:nil];
153     _pipViewController = nil;
154     [_videoViewContainer removeFromSuperview];
155     [_videoViewContainer setVideoViewContainerDelegate:nil];
156     _videoViewContainer = nil;
157     _videoViewContainerController = nil;
158     _pipState = PIPState::NotInPIP;
159     _exitingToStandardFullscreen = NO;
160     _returningWindow = nil;
161     _returningRect = NSZeroRect;
162 }
163
164 - (void)invalidate
165 {
166     [self invalidateFullscreenState];
167     _videoFullscreenInterfaceMac = nullptr;
168     _videoDimensions = NSZeroSize;
169 }
170
171 - (void)updateIsPlaying:(BOOL)isPlaying newPlaybackRate:(float)playbackRate
172 {
173     _playing = isPlaying && playbackRate;
174
175     [_pipViewController setPlaying:_playing];
176 }
177
178 - (void)setVideoDimensions:(NSSize)videoDimensions
179 {
180     _videoDimensions = videoDimensions;
181
182     [_pipViewController setAspectRatio:_videoDimensions];
183 }
184
185 - (void)setUpPIPForVideoView:(NSView *)videoView withFrame:(NSRect)frame inWindow:(NSWindow *)window
186 {
187     ASSERT(!_pipViewController);
188     ASSERT(!_videoViewContainerController);
189     ASSERT(!_videoViewContainer);
190
191     _pipViewController = adoptNS([allocPIPViewControllerInstance() init]);
192     [_pipViewController setDelegate:self];
193     [_pipViewController setUserCanResize:YES];
194     [_pipViewController setPlaying:_playing];
195     [self setVideoDimensions:NSEqualSizes(_videoDimensions, NSZeroSize) ? frame.size : _videoDimensions];
196     if (_videoFullscreenInterfaceMac && _videoFullscreenInterfaceMac->videoFullscreenModel())
197         _videoFullscreenInterfaceMac->videoFullscreenModel()->setVideoLayerGravity(MediaPlayerEnums::VideoGravityResizeAspectFill);
198
199     _videoViewContainer = adoptNS([[WebVideoViewContainer alloc] initWithFrame:frame]);
200     [_videoViewContainer setVideoViewContainerDelegate:self];
201     [_videoViewContainer addSubview:videoView];
202     videoView.frame = [_videoViewContainer bounds];
203     videoView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
204
205     _videoViewContainerController = adoptNS([[NSViewController alloc] init]);
206     [_videoViewContainerController setView:_videoViewContainer.get()];
207     [window.contentView addSubview:_videoViewContainer.get() positioned:NSWindowAbove relativeTo:nil];
208 }
209
210 - (void)enterPIP
211 {
212     if (_pipState == PIPState::InPIP)
213         return;
214
215     [_videoViewContainerController view].layer.backgroundColor = CGColorGetConstantColor(kCGColorBlack);
216     [_pipViewController presentViewControllerAsPictureInPicture:_videoViewContainerController.get()];
217     _pipState = PIPState::InPIP;
218 }
219
220 - (void)exitPIP
221 {
222     if (_pipState != PIPState::InPIP || !_pipViewController || !_videoViewContainerController)
223         return;
224
225     [_videoViewContainerController view].layer.backgroundColor = CGColorGetConstantColor(kCGColorClear);
226     [_pipViewController dismissViewController:_videoViewContainerController.get()];
227     _pipState = PIPState::ExitingPIP;
228 }
229
230 - (void)exitPIPAnimatingToRect:(NSRect)rect inWindow:(NSWindow *)window
231 {
232     _returningWindow = window;
233     _returningRect = rect;
234
235     [_pipViewController setReplacementRect:rect];
236     [_pipViewController setReplacementWindow:window];
237
238     [self exitPIP];
239 }
240
241 // WebVideoViewContainerDelegate
242
243 - (void)boundsDidChangeForVideoViewContainer:(WebVideoViewContainer *)videoViewContainer
244 {
245     if (!_videoViewContainer || !_pipViewController)
246         return;
247
248     ASSERT_UNUSED(videoViewContainer, videoViewContainer == _videoViewContainer);
249
250     if (_videoFullscreenInterfaceMac && _videoFullscreenInterfaceMac->videoFullscreenModel())
251         _videoFullscreenInterfaceMac->videoFullscreenModel()->setVideoLayerFrame([_videoViewContainer bounds]);
252 }
253
254 - (void)superviewDidChangeForVideoViewContainer:(WebVideoViewContainer *)videoViewContainer
255 {
256     if (!_videoViewContainer || !_pipViewController)
257         return;
258
259     ASSERT(videoViewContainer == _videoViewContainer);
260
261     if (![videoViewContainer isDescendantOf:[_pipViewController view]])
262         return;
263
264     // Once the view is moved into the pip view, make sure it resizes with the pip view.
265     videoViewContainer.frame = [videoViewContainer superview].bounds;
266     videoViewContainer.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
267 }
268
269 // PIPViewControllerDelegate
270
271 - (BOOL)pipShouldClose:(PIPViewController *)pip
272 {
273     ASSERT_UNUSED(pip, pip == _pipViewController);
274
275     if (!_videoFullscreenInterfaceMac)
276         return YES;
277     
278     if (_videoFullscreenInterfaceMac->videoFullscreenChangeObserver())
279         _videoFullscreenInterfaceMac->videoFullscreenChangeObserver()->fullscreenMayReturnToInline();
280
281     _videoFullscreenInterfaceMac->requestHideAndExitPiP();
282
283     return NO;
284 }
285
286 - (void)pipDidClose:(PIPViewController *)pip
287 {
288     ASSERT_UNUSED(pip, pip == _pipViewController);
289
290     if (!_videoFullscreenInterfaceMac)
291         return;
292
293     if (_pipState != PIPState::ExitingPIP) {
294         // We got told to close without going through -pipActionStop, nor by exlicitly being asked to in -exitPiP:.
295         // Call -pipActionStop: here in order to set the fullscreen state to an expected value.
296         [self pipActionStop:pip];
297     }
298
299     if (_videoFullscreenInterfaceMac->videoFullscreenModel() && _videoViewContainer && _returningWindow && !NSEqualRects(_returningRect, NSZeroRect)) {
300         [NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
301             context.allowsImplicitAnimation = NO;
302             [_videoViewContainer setFrame:_returningRect];
303             _videoFullscreenInterfaceMac->videoFullscreenModel()->setVideoLayerFrame([_videoViewContainer bounds]);
304             _videoFullscreenInterfaceMac->videoFullscreenModel()->setVideoLayerGravity(MediaPlayerEnums::VideoGravityResizeAspect);
305
306             [[_returningWindow contentView] addSubview:_videoViewContainer.get() positioned:NSWindowAbove relativeTo:nil];
307         } completionHandler:nil];
308     }
309
310     if (!self.isExitingToStandardFullscreen) {
311         if (VideoFullscreenModel* videoFullscreenModel = _videoFullscreenInterfaceMac->videoFullscreenModel()) {
312             videoFullscreenModel->didExitPictureInPicture();
313             videoFullscreenModel->setVideoLayerGravity(MediaPlayerEnums::VideoGravityResizeAspect);
314         }
315     }
316
317     if (VideoFullscreenChangeObserver* fullscreenChangeObserver = _videoFullscreenInterfaceMac->videoFullscreenChangeObserver())
318         fullscreenChangeObserver->didExitFullscreen();
319
320     _videoFullscreenInterfaceMac->clearMode(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture);
321 }
322
323 - (void)pipActionPlay:(PIPViewController *)pip
324 {
325     ASSERT_UNUSED(pip, pip == _pipViewController);
326
327     if (_videoFullscreenInterfaceMac && _videoFullscreenInterfaceMac->playbackSessionModel())
328         _videoFullscreenInterfaceMac->playbackSessionModel()->play();
329 }
330
331 - (void)pipActionPause:(PIPViewController *)pip
332 {
333     ASSERT_UNUSED(pip, pip == _pipViewController);
334
335     if (_videoFullscreenInterfaceMac && _videoFullscreenInterfaceMac->playbackSessionModel())
336         _videoFullscreenInterfaceMac->playbackSessionModel()->pause();
337 }
338
339 - (void)pipActionStop:(PIPViewController *)pip
340 {
341     ASSERT_UNUSED(pip, pip == _pipViewController);
342
343     if (!_videoFullscreenInterfaceMac)
344         return;
345
346     if (PlaybackSessionModel* playbackSessionModel = _videoFullscreenInterfaceMac->playbackSessionModel())
347         playbackSessionModel->pause();
348
349     _videoFullscreenInterfaceMac->requestHideAndExitPiP();
350     _pipState = PIPState::ExitingPIP;
351 }
352
353 @end
354
355 namespace WebCore {
356 using namespace PAL;
357
358 VideoFullscreenInterfaceMac::VideoFullscreenInterfaceMac(PlaybackSessionInterfaceMac& playbackSessionInterface)
359     : m_playbackSessionInterface(playbackSessionInterface)
360 {
361     ASSERT(m_playbackSessionInterface->playbackSessionModel());
362     auto model = m_playbackSessionInterface->playbackSessionModel();
363     model->addClient(*this);
364     [videoFullscreenInterfaceObjC() updateIsPlaying:model->isPlaying() newPlaybackRate:model->playbackRate()];
365 }
366
367 VideoFullscreenInterfaceMac::~VideoFullscreenInterfaceMac()
368 {
369     if (auto* model = m_playbackSessionInterface->playbackSessionModel())
370         model->removeClient(*this);
371     if (m_videoFullscreenModel)
372         m_videoFullscreenModel->removeClient(*this);
373 }
374
375 void VideoFullscreenInterfaceMac::setVideoFullscreenModel(VideoFullscreenModel* model)
376 {
377     if (m_videoFullscreenModel)
378         m_videoFullscreenModel->removeClient(*this);
379     m_videoFullscreenModel = makeWeakPtr(model);
380     if (m_videoFullscreenModel)
381         m_videoFullscreenModel->addClient(*this);
382 }
383
384 void VideoFullscreenInterfaceMac::setVideoFullscreenChangeObserver(VideoFullscreenChangeObserver* observer)
385 {
386     m_fullscreenChangeObserver = makeWeakPtr(observer);
387 }
388
389 void VideoFullscreenInterfaceMac::setMode(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::clearMode(HTMLMediaElementEnums::VideoFullscreenMode mode)
401 {
402     HTMLMediaElementEnums::VideoFullscreenMode newMode = m_mode & ~mode;
403     if (m_mode == newMode)
404         return;
405
406     m_mode = newMode;
407     if (m_videoFullscreenModel)
408         m_videoFullscreenModel->fullscreenModeChanged(m_mode);
409 }
410
411 void VideoFullscreenInterfaceMac::rateChanged(bool isPlaying, float playbackRate)
412 {
413     [videoFullscreenInterfaceObjC() updateIsPlaying:isPlaying newPlaybackRate:playbackRate];
414 }
415
416 void VideoFullscreenInterfaceMac::ensureControlsManager()
417 {
418     m_playbackSessionInterface->ensureControlsManager();
419 }
420
421 WebVideoFullscreenInterfaceMacObjC *VideoFullscreenInterfaceMac::videoFullscreenInterfaceObjC()
422 {
423     if (!m_webVideoFullscreenInterfaceObjC)
424         m_webVideoFullscreenInterfaceObjC = adoptNS([[WebVideoFullscreenInterfaceMacObjC alloc] initWithVideoFullscreenInterfaceMac:this]);
425
426     return m_webVideoFullscreenInterfaceObjC.get();
427 }
428
429 void VideoFullscreenInterfaceMac::setupFullscreen(NSView& layerHostedView, const IntRect& initialRect, NSWindow *parentWindow, HTMLMediaElementEnums::VideoFullscreenMode mode, bool allowsPictureInPicturePlayback)
430 {
431     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);
432
433     UNUSED_PARAM(allowsPictureInPicturePlayback);
434     ASSERT(mode == HTMLMediaElementEnums::VideoFullscreenModePictureInPicture);
435
436     m_mode = mode;
437
438     [videoFullscreenInterfaceObjC() setUpPIPForVideoView:&layerHostedView withFrame:(NSRect)initialRect inWindow:parentWindow];
439
440     dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), this] {
441         if (m_fullscreenChangeObserver)
442             m_fullscreenChangeObserver->didSetupFullscreen();
443     });
444 }
445
446 void VideoFullscreenInterfaceMac::enterFullscreen()
447 {
448     LOG(Fullscreen, "VideoFullscreenInterfaceMac::enterFullscreen(%p)", this);
449
450     RELEASE_ASSERT(m_videoFullscreenModel);
451     if (mode() == HTMLMediaElementEnums::VideoFullscreenModePictureInPicture) {
452         m_videoFullscreenModel->willEnterPictureInPicture();
453         [m_webVideoFullscreenInterfaceObjC enterPIP];
454
455 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
456         [m_playbackSessionInterface->playBackControlsManager() setPictureInPictureActive:YES];
457 #endif
458
459         // FIXME(rdar://problem/42250952): Move this call into a completion handler or delegate callback.
460         m_videoFullscreenModel->didEnterPictureInPicture();
461         if (m_fullscreenChangeObserver)
462             m_fullscreenChangeObserver->didEnterFullscreen();
463     }
464 }
465
466 void VideoFullscreenInterfaceMac::exitFullscreen(const IntRect& finalRect, NSWindow *parentWindow)
467 {
468     LOG(Fullscreen, "VideoFullscreenInterfaceMac::exitFullscreen(%p), finalRect:{%d, %d, %d, %d}, parentWindow:%p", this, finalRect.x(), finalRect.y(), finalRect.width(), finalRect.height(), parentWindow);
469
470 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
471     [m_playbackSessionInterface->playBackControlsManager() setPictureInPictureActive:NO];
472 #endif
473
474     if (finalRect.isEmpty())
475         [m_webVideoFullscreenInterfaceObjC exitPIP];
476     else
477         [m_webVideoFullscreenInterfaceObjC exitPIPAnimatingToRect:finalRect inWindow:parentWindow];
478 }
479
480 void VideoFullscreenInterfaceMac::exitFullscreenWithoutAnimationToMode(HTMLMediaElementEnums::VideoFullscreenMode mode)
481 {
482     LOG(Fullscreen, "VideoFullscreenInterfaceMac::exitFullscreenWithoutAnimationToMode(%p), mode:%d", this, mode);
483
484 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
485     [m_playbackSessionInterface->playBackControlsManager() setPictureInPictureActive:NO];
486 #endif
487
488     bool isExitingToStandardFullscreen = mode == HTMLMediaElementEnums::VideoFullscreenModeStandard;
489     // On Mac, standard fullscreen is handled by the Fullscreen API and not by VideoFullscreenManager.
490     // Just update m_mode directly to HTMLMediaElementEnums::VideoFullscreenModeStandard in that case to keep
491     // m_mode in sync with the fullscreen mode in HTMLMediaElement.
492     if (isExitingToStandardFullscreen)
493         m_mode = HTMLMediaElementEnums::VideoFullscreenModeStandard;
494
495     [m_webVideoFullscreenInterfaceObjC setExitingToStandardFullscreen:isExitingToStandardFullscreen];
496     [m_webVideoFullscreenInterfaceObjC exitPIP];
497 }
498
499 void VideoFullscreenInterfaceMac::cleanupFullscreen()
500 {
501     LOG(Fullscreen, "VideoFullscreenInterfaceMac::cleanupFullscreen(%p)", this);
502
503     [m_webVideoFullscreenInterfaceObjC exitPIP];
504     [m_webVideoFullscreenInterfaceObjC invalidateFullscreenState];
505
506     if (m_fullscreenChangeObserver)
507         m_fullscreenChangeObserver->didCleanupFullscreen();
508 }
509
510 void VideoFullscreenInterfaceMac::invalidate()
511 {
512     LOG(Fullscreen, "VideoFullscreenInterfaceMac::invalidate(%p)", this);
513
514     m_videoFullscreenModel = nullptr;
515     m_fullscreenChangeObserver = nullptr;
516
517     cleanupFullscreen();
518
519     [m_webVideoFullscreenInterfaceObjC invalidate];
520     m_webVideoFullscreenInterfaceObjC = nil;
521 }
522
523 void VideoFullscreenInterfaceMac::requestHideAndExitPiP()
524 {
525     if (!m_videoFullscreenModel)
526         return;
527
528     m_videoFullscreenModel->requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
529     m_videoFullscreenModel->willExitPictureInPicture();
530 }
531
532 #if !LOG_DISABLED
533 static const char* boolString(bool val)
534 {
535     return val ? "true" : "false";
536 }
537 #endif
538
539 void VideoFullscreenInterfaceMac::preparedToReturnToInline(bool visible, const IntRect& inlineRect, NSWindow *parentWindow)
540 {
541     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);
542
543     if (!visible) {
544         [m_webVideoFullscreenInterfaceObjC exitPIP];
545         return;
546     }
547
548     ASSERT(parentWindow);
549     [m_webVideoFullscreenInterfaceObjC exitPIPAnimatingToRect:(NSRect)inlineRect inWindow:parentWindow];
550 }
551
552 void VideoFullscreenInterfaceMac::externalPlaybackChanged(bool enabled, PlaybackSessionModel::ExternalPlaybackTargetType, const String&)
553 {
554     LOG(Fullscreen, "VideoFullscreenInterfaceMac::externalPlaybackChanged(%p), enabled:%s", this, boolString(enabled));
555
556     if (enabled && m_mode == HTMLMediaElementEnums::VideoFullscreenModePictureInPicture)
557         exitFullscreen(IntRect(), nil);
558 }
559
560 void VideoFullscreenInterfaceMac::hasVideoChanged(bool hasVideo)
561 {
562     LOG(Fullscreen, "VideoFullscreenInterfaceMac::hasVideoChanged(%p):%s", this, boolString(hasVideo));
563
564     if (!hasVideo)
565         exitFullscreenWithoutAnimationToMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
566 }
567
568 void VideoFullscreenInterfaceMac::videoDimensionsChanged(const FloatSize& videoDimensions)
569 {
570     LOG(Fullscreen, "VideoFullscreenInterfaceMac::videoDimensionsChanged(%p), width:%.0f, height:%.0f", this, videoDimensions.width(), videoDimensions.height());
571
572     // Width and height can be zero when we are transitioning from one video to another. Ignore zero values.
573     if (!videoDimensions.isZero())
574         [m_webVideoFullscreenInterfaceObjC setVideoDimensions:videoDimensions];
575 }
576
577 bool VideoFullscreenInterfaceMac::isPlayingVideoInEnhancedFullscreen() const
578 {
579     return hasMode(WebCore::HTMLMediaElementEnums::VideoFullscreenModePictureInPicture) && [m_webVideoFullscreenInterfaceObjC isPlaying];
580 }
581
582 bool supportsPictureInPicture()
583 {
584     return PIPLibrary() && getPIPViewControllerClass();
585 }
586
587 }
588
589 #endif