Enable picture-in-picture from inline element on suspend.
[WebKit-https.git] / Source / WebKit / WebProcess / cocoa / VideoFullscreenManager.mm
1 /*
2  * Copyright (C) 2014-2017 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. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 #import "config.h"
26 #import "VideoFullscreenManager.h"
27
28 #if (PLATFORM(IOS) && HAVE(AVKIT)) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
29
30 #import "Attachment.h"
31 #import "Logging.h"
32 #import "PlaybackSessionManager.h"
33 #import "VideoFullscreenManagerMessages.h"
34 #import "VideoFullscreenManagerProxyMessages.h"
35 #import "WebCoreArgumentCoders.h"
36 #import "WebPage.h"
37 #import "WebProcess.h"
38 #import <QuartzCore/CoreAnimation.h>
39 #import <WebCore/Color.h>
40 #import <WebCore/DeprecatedGlobalSettings.h>
41 #import <WebCore/Event.h>
42 #import <WebCore/EventNames.h>
43 #import <WebCore/FrameView.h>
44 #import <WebCore/HTMLVideoElement.h>
45 #import <WebCore/PlatformCALayer.h>
46 #import <WebCore/RenderLayer.h>
47 #import <WebCore/RenderLayerBacking.h>
48 #import <WebCore/RenderVideo.h>
49 #import <WebCore/RenderView.h>
50 #import <WebCore/Settings.h>
51 #import <WebCore/TimeRanges.h>
52 #import <WebCore/WebActionDisablingCALayerDelegate.h>
53 #import <mach/mach_port.h>
54
55 using namespace WebCore;
56
57 namespace WebKit {
58
59 static IntRect inlineVideoFrame(HTMLVideoElement& element)
60 {
61     element.document().updateLayoutIgnorePendingStylesheets();
62     auto* renderer = element.renderer();
63     if (!renderer)
64         return { };
65
66     if (renderer->hasLayer() && renderer->enclosingLayer()->isComposited()) {
67         FloatQuad contentsBox = static_cast<FloatRect>(renderer->enclosingLayer()->backing()->contentsBox());
68         contentsBox = renderer->localToAbsoluteQuad(contentsBox);
69         return element.document().view()->contentsToRootView(contentsBox.enclosingBoundingBox());
70     }
71
72     auto rect = renderer->videoBox();
73     rect.moveBy(renderer->absoluteBoundingBoxRect().location());
74     return element.document().view()->contentsToRootView(rect);
75 }
76
77 #pragma mark - VideoFullscreenInterfaceContext
78
79 VideoFullscreenInterfaceContext::VideoFullscreenInterfaceContext(VideoFullscreenManager& manager, uint64_t contextId)
80     : m_manager(&manager)
81     , m_contextId(contextId)
82 {
83 }
84
85 VideoFullscreenInterfaceContext::~VideoFullscreenInterfaceContext()
86 {
87 }
88
89 void VideoFullscreenInterfaceContext::setLayerHostingContext(std::unique_ptr<LayerHostingContext>&& context)
90 {
91     m_layerHostingContext = WTFMove(context);
92 }
93
94 void VideoFullscreenInterfaceContext::hasVideoChanged(bool hasVideo)
95 {
96     if (m_manager)
97         m_manager->hasVideoChanged(m_contextId, hasVideo);
98 }
99
100 void VideoFullscreenInterfaceContext::videoDimensionsChanged(const FloatSize& videoDimensions)
101 {
102     if (m_manager)
103         m_manager->videoDimensionsChanged(m_contextId, videoDimensions);
104 }
105
106 #pragma mark - VideoFullscreenManager
107
108 Ref<VideoFullscreenManager> VideoFullscreenManager::create(WebPage& page, PlaybackSessionManager& playbackSessionManager)
109 {
110     return adoptRef(*new VideoFullscreenManager(page, playbackSessionManager));
111 }
112
113 VideoFullscreenManager::VideoFullscreenManager(WebPage& page, PlaybackSessionManager& playbackSessionManager)
114     : m_page(&page)
115     , m_playbackSessionManager(playbackSessionManager)
116 {
117     WebProcess::singleton().addMessageReceiver(Messages::VideoFullscreenManager::messageReceiverName(), page.pageID(), *this);
118 }
119
120 VideoFullscreenManager::~VideoFullscreenManager()
121 {
122     for (auto& tuple : m_contextMap.values()) {
123         RefPtr<VideoFullscreenModelVideoElement> model;
124         RefPtr<VideoFullscreenInterfaceContext> interface;
125         std::tie(model, interface) = tuple;
126
127         model->setVideoElement(nullptr);
128         model->removeClient(*interface);
129
130         interface->invalidate();
131     }
132
133     m_contextMap.clear();
134     m_videoElements.clear();
135     m_clientCounts.clear();
136     
137     if (m_page)
138         WebProcess::singleton().removeMessageReceiver(Messages::VideoFullscreenManager::messageReceiverName(), m_page->pageID());
139 }
140
141 void VideoFullscreenManager::invalidate()
142 {
143     ASSERT(m_page);
144     WebProcess::singleton().removeMessageReceiver(Messages::VideoFullscreenManager::messageReceiverName(), m_page->pageID());
145     m_page = nullptr;
146 }
147
148 VideoFullscreenManager::ModelInterfaceTuple VideoFullscreenManager::createModelAndInterface(uint64_t contextId)
149 {
150     RefPtr<VideoFullscreenModelVideoElement> model = VideoFullscreenModelVideoElement::create();
151     RefPtr<VideoFullscreenInterfaceContext> interface = VideoFullscreenInterfaceContext::create(*this, contextId);
152     m_playbackSessionManager->addClientForContext(contextId);
153
154     interface->setLayerHostingContext(LayerHostingContext::createForExternalHostingProcess());
155     model->addClient(*interface);
156
157     return std::make_tuple(WTFMove(model), WTFMove(interface));
158 }
159
160 VideoFullscreenManager::ModelInterfaceTuple& VideoFullscreenManager::ensureModelAndInterface(uint64_t contextId)
161 {
162     auto addResult = m_contextMap.add(contextId, ModelInterfaceTuple());
163     if (addResult.isNewEntry)
164         addResult.iterator->value = createModelAndInterface(contextId);
165     return addResult.iterator->value;
166 }
167
168 WebCore::VideoFullscreenModelVideoElement& VideoFullscreenManager::ensureModel(uint64_t contextId)
169 {
170     return *std::get<0>(ensureModelAndInterface(contextId));
171 }
172
173 VideoFullscreenInterfaceContext& VideoFullscreenManager::ensureInterface(uint64_t contextId)
174 {
175     return *std::get<1>(ensureModelAndInterface(contextId));
176 }
177
178 void VideoFullscreenManager::removeContext(uint64_t contextId)
179 {
180     RefPtr<VideoFullscreenModelVideoElement> model;
181     RefPtr<VideoFullscreenInterfaceContext> interface;
182     std::tie(model, interface) = ensureModelAndInterface(contextId);
183
184     m_playbackSessionManager->removeClientForContext(contextId);
185
186     RefPtr<HTMLVideoElement> videoElement = model->videoElement();
187     model->setVideoElement(nullptr);
188     model->removeClient(*interface);
189     interface->invalidate();
190     m_videoElements.remove(videoElement.get());
191     m_contextMap.remove(contextId);
192 }
193
194 void VideoFullscreenManager::addClientForContext(uint64_t contextId)
195 {
196     auto addResult = m_clientCounts.add(contextId, 1);
197     if (!addResult.isNewEntry)
198         addResult.iterator->value++;
199 }
200
201 void VideoFullscreenManager::removeClientForContext(uint64_t contextId)
202 {
203     ASSERT(m_clientCounts.contains(contextId));
204
205     int clientCount = m_clientCounts.get(contextId);
206     ASSERT(clientCount > 0);
207     clientCount--;
208
209     if (clientCount <= 0) {
210         m_clientCounts.remove(contextId);
211         removeContext(contextId);
212         return;
213     }
214
215     m_clientCounts.set(contextId, clientCount);
216 }
217
218 #pragma mark Interface to ChromeClient:
219
220 bool VideoFullscreenManager::supportsVideoFullscreen(WebCore::HTMLMediaElementEnums::VideoFullscreenMode mode) const
221 {
222 #if PLATFORM(IOS)
223     UNUSED_PARAM(mode);
224     return DeprecatedGlobalSettings::avKitEnabled();
225 #else
226     return mode == HTMLMediaElementEnums::VideoFullscreenModePictureInPicture && supportsPictureInPicture();
227 #endif
228 }
229
230 bool VideoFullscreenManager::supportsVideoFullscreenStandby() const
231 {
232 #if PLATFORM(IOS) && ENABLE(FULLSCREEN_API)
233     return true;
234 #else
235     return false;
236 #endif
237 }
238
239 void VideoFullscreenManager::enterVideoFullscreenForVideoElement(HTMLVideoElement& videoElement, HTMLMediaElementEnums::VideoFullscreenMode mode, bool standby)
240 {
241     ASSERT(m_page);
242     ASSERT(standby || mode != HTMLMediaElementEnums::VideoFullscreenModeNone);
243     LOG(Fullscreen, "VideoFullscreenManager::enterVideoFullscreenForVideoElement(%p)", this);
244
245     uint64_t contextId = m_playbackSessionManager->contextIdForMediaElement(videoElement);
246     auto addResult = m_videoElements.add(&videoElement, contextId);
247     UNUSED_PARAM(addResult);
248     ASSERT(addResult.iterator->value == contextId);
249
250     RefPtr<VideoFullscreenModelVideoElement> model;
251     RefPtr<VideoFullscreenInterfaceContext> interface;
252     std::tie(model, interface) = ensureModelAndInterface(contextId);
253     addClientForContext(contextId);
254     if (!interface->layerHostingContext())
255         interface->setLayerHostingContext(LayerHostingContext::createForExternalHostingProcess());
256
257     auto videoRect = inlineVideoFrame(videoElement);
258     FloatRect videoLayerFrame = FloatRect(0, 0, videoRect.width(), videoRect.height());
259
260     HTMLMediaElementEnums::VideoFullscreenMode oldMode = interface->fullscreenMode();
261     interface->setTargetIsFullscreen(true);
262     interface->setFullscreenMode(mode);
263     interface->setFullscreenStandby(standby);
264     model->setVideoElement(&videoElement);
265     if (oldMode == HTMLMediaElementEnums::VideoFullscreenModeNone && mode != HTMLMediaElementEnums::VideoFullscreenModeNone)
266         model->setVideoLayerFrame(videoLayerFrame);
267
268     if (interface->isAnimating())
269         return;
270     interface->setIsAnimating(true);
271
272     bool allowsPictureInPicture = videoElement.webkitSupportsPresentationMode(HTMLVideoElement::VideoPresentationMode::PictureInPicture);
273
274     if (!interface->layerHostingContext()->rootLayer()) {
275         PlatformLayer* videoLayer = [CALayer layer];
276         [videoLayer setDelegate:[WebActionDisablingCALayerDelegate shared]];
277
278         [videoLayer setName:@"Web video fullscreen manager layer"];
279         [videoLayer setPosition:CGPointMake(0, 0)];
280         [videoLayer setBackgroundColor:cachedCGColor(WebCore::Color::transparent)];
281
282         // Set a scale factor here to make convertRect:toLayer:nil take scale factor into account. <rdar://problem/18316542>.
283         // This scale factor is inverted in the hosting process.
284         float hostingScaleFactor = m_page->deviceScaleFactor();
285         [videoLayer setTransform:CATransform3DMakeScale(hostingScaleFactor, hostingScaleFactor, 1)];
286
287         interface->layerHostingContext()->setRootLayer(videoLayer);
288     }
289
290     m_page->send(Messages::VideoFullscreenManagerProxy::SetupFullscreenWithID(contextId, interface->layerHostingContext()->contextID(), videoRect, m_page->deviceScaleFactor(), interface->fullscreenMode(), allowsPictureInPicture, standby), m_page->pageID());
291 }
292
293 void VideoFullscreenManager::exitVideoFullscreenForVideoElement(WebCore::HTMLVideoElement& videoElement)
294 {
295     LOG(Fullscreen, "VideoFullscreenManager::exitVideoFullscreenForVideoElement(%p)", this);
296     ASSERT(m_page);
297     ASSERT(m_videoElements.contains(&videoElement));
298
299     uint64_t contextId = m_videoElements.get(&videoElement);
300     auto& interface = ensureInterface(contextId);
301
302     interface.setTargetIsFullscreen(false);
303
304     if (interface.isAnimating())
305         return;
306
307     interface.setIsAnimating(true);
308     m_page->send(Messages::VideoFullscreenManagerProxy::ExitFullscreen(contextId, inlineVideoFrame(videoElement)), m_page->pageID());
309 }
310
311 void VideoFullscreenManager::exitVideoFullscreenToModeWithoutAnimation(WebCore::HTMLVideoElement& videoElement, WebCore::HTMLMediaElementEnums::VideoFullscreenMode targetMode)
312 {
313     LOG(Fullscreen, "VideoFullscreenManager::exitVideoFullscreenToModeWithoutAnimation(%p)", this);
314
315 #if PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE)
316     ASSERT(m_page);
317     ASSERT(m_videoElements.contains(&videoElement));
318
319     uint64_t contextId = m_videoElements.get(&videoElement);
320     auto& interface = ensureInterface(contextId);
321
322     interface.setTargetIsFullscreen(false);
323
324     m_page->send(Messages::VideoFullscreenManagerProxy::ExitFullscreenWithoutAnimationToMode(contextId, targetMode), m_page->pageID());
325 #else
326     UNUSED_PARAM(videoElement);
327     UNUSED_PARAM(targetMode);
328 #endif
329 }
330
331 #pragma mark Interface to VideoFullscreenInterfaceContext:
332
333 void VideoFullscreenManager::hasVideoChanged(uint64_t contextId, bool hasVideo)
334 {
335     if (m_page)
336         m_page->send(Messages::VideoFullscreenManagerProxy::SetHasVideo(contextId, hasVideo), m_page->pageID());
337 }
338
339 void VideoFullscreenManager::videoDimensionsChanged(uint64_t contextId, const FloatSize& videoDimensions)
340 {
341     if (m_page)
342         m_page->send(Messages::VideoFullscreenManagerProxy::SetVideoDimensions(contextId, videoDimensions), m_page->pageID());
343 }
344
345 #pragma mark Messages from VideoFullscreenManagerProxy:
346
347 void VideoFullscreenManager::requestFullscreenMode(uint64_t contextId, WebCore::HTMLMediaElementEnums::VideoFullscreenMode mode, bool finishedWithMedia)
348 {
349     ensureModel(contextId).requestFullscreenMode(mode, finishedWithMedia);
350 }
351
352 void VideoFullscreenManager::fullscreenModeChanged(uint64_t contextId, WebCore::HTMLMediaElementEnums::VideoFullscreenMode videoFullscreenMode)
353 {
354     ensureModel(contextId).fullscreenModeChanged(videoFullscreenMode);
355 }
356
357 void VideoFullscreenManager::requestUpdateInlineRect(uint64_t contextId)
358 {
359     if (!m_page)
360         return;
361
362     auto& model = ensureModel(contextId);
363     IntRect inlineRect = inlineVideoFrame(*model.videoElement());
364     m_page->send(Messages::VideoFullscreenManagerProxy::SetInlineRect(contextId, inlineRect, inlineRect != IntRect(0, 0, 0, 0)), m_page->pageID());
365 }
366
367 void VideoFullscreenManager::requestVideoContentLayer(uint64_t contextId)
368 {
369     RefPtr<VideoFullscreenModelVideoElement> model;
370     RefPtr<VideoFullscreenInterfaceContext> interface;
371     std::tie(model, interface) = ensureModelAndInterface(contextId);
372
373     CALayer* videoLayer = interface->layerHostingContext()->rootLayer();
374
375     model->setVideoFullscreenLayer(videoLayer, [protectedThis = makeRefPtr(this), this, contextId] () mutable {
376         dispatch_async(dispatch_get_main_queue(), [protectedThis = WTFMove(protectedThis), this, contextId] {
377             if (protectedThis->m_page)
378                 m_page->send(Messages::VideoFullscreenManagerProxy::SetHasVideoContentLayer(contextId, true), protectedThis->m_page->pageID());
379         });
380     });
381 }
382
383 void VideoFullscreenManager::returnVideoContentLayer(uint64_t contextId)
384 {
385     RefPtr<VideoFullscreenModelVideoElement> model;
386     RefPtr<VideoFullscreenInterfaceContext> interface;
387     std::tie(model, interface) = ensureModelAndInterface(contextId);
388
389     model->waitForPreparedForInlineThen([protectedThis = makeRefPtr(this), this, contextId, model] () mutable { // need this for return video layer
390         dispatch_async(dispatch_get_main_queue(), [protectedThis = WTFMove(protectedThis), this, contextId, model] () mutable {
391             model->setVideoFullscreenLayer(nil, [protectedThis = WTFMove(protectedThis), this, contextId] () mutable {
392                 dispatch_async(dispatch_get_main_queue(), [protectedThis = WTFMove(protectedThis), this, contextId] {
393                     if (protectedThis->m_page)
394                         m_page->send(Messages::VideoFullscreenManagerProxy::SetHasVideoContentLayer(contextId, false), protectedThis->m_page->pageID());
395                 });
396             });
397         });
398     });
399 }
400
401 void VideoFullscreenManager::didSetupFullscreen(uint64_t contextId)
402 {
403     LOG(Fullscreen, "VideoFullscreenManager::didSetupFullscreen(%p, %x)", this, contextId);
404
405     ASSERT(m_page);
406     RefPtr<VideoFullscreenModelVideoElement> model;
407     RefPtr<VideoFullscreenInterfaceContext> interface;
408     std::tie(model, interface) = ensureModelAndInterface(contextId);
409
410 #if PLATFORM(IOS) && ENABLE(FULLSCREEN_API)
411     dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), this, contextId] {
412         if (protectedThis->m_page)
413             m_page->send(Messages::VideoFullscreenManagerProxy::EnterFullscreen(contextId), protectedThis->m_page->pageID());
414     });
415 #else
416     CALayer* videoLayer = interface->layerHostingContext()->rootLayer();
417
418     model->setVideoFullscreenLayer(videoLayer, [protectedThis = makeRefPtr(this), this, contextId] () mutable {
419         dispatch_async(dispatch_get_main_queue(), [protectedThis = WTFMove(protectedThis), this, contextId] {
420             if (protectedThis->m_page)
421                 m_page->send(Messages::VideoFullscreenManagerProxy::EnterFullscreen(contextId), protectedThis->m_page->pageID());
422         });
423     });
424 #endif
425 }
426     
427 void VideoFullscreenManager::didEnterFullscreen(uint64_t contextId)
428 {
429     LOG(Fullscreen, "VideoFullscreenManager::didEnterFullscreen(%p, %x)", this, contextId);
430
431     RefPtr<VideoFullscreenModelVideoElement> model;
432     RefPtr<VideoFullscreenInterfaceContext> interface;
433     std::tie(model, interface) = ensureModelAndInterface(contextId);
434
435     interface->setIsAnimating(false);
436     interface->setIsFullscreen(false);
437
438     if (interface->targetIsFullscreen())
439         return;
440
441     RefPtr<HTMLVideoElement> videoElement = model->videoElement();
442     if (!videoElement)
443         return;
444
445     // exit fullscreen now if it was previously requested during an animation.
446     dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), videoElement] {
447         if (protectedThis->m_page)
448             protectedThis->exitVideoFullscreenForVideoElement(*videoElement);
449     });
450 }
451
452 void VideoFullscreenManager::didExitFullscreen(uint64_t contextId)
453 {
454     LOG(Fullscreen, "VideoFullscreenManager::didExitFullscreen(%p, %x)", this, contextId);
455
456     RefPtr<VideoFullscreenModelVideoElement> model;
457     RefPtr<VideoFullscreenInterfaceContext> interface;
458     std::tie(model, interface) = ensureModelAndInterface(contextId);
459
460 #if PLATFORM(IOS) && ENABLE(FULLSCREEN_API)
461     dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), contextId, interface] {
462         if (protectedThis->m_page)
463             protectedThis->m_page->send(Messages::VideoFullscreenManagerProxy::CleanupFullscreen(contextId), protectedThis->m_page->pageID());
464     });
465 #else
466     model->waitForPreparedForInlineThen([protectedThis = makeRefPtr(this), contextId, interface, model] () mutable {
467         dispatch_async(dispatch_get_main_queue(), [protectedThis = WTFMove(protectedThis), contextId, interface, model] () mutable {
468             model->setVideoFullscreenLayer(nil, [protectedThis = WTFMove(protectedThis), contextId, interface] () mutable {
469                 dispatch_async(dispatch_get_main_queue(), [protectedThis = WTFMove(protectedThis), contextId, interface] {
470                     if (interface->layerHostingContext()) {
471                         interface->layerHostingContext()->setRootLayer(nullptr);
472                         interface->setLayerHostingContext(nullptr);
473                     }
474                     if (protectedThis->m_page)
475                         protectedThis->m_page->send(Messages::VideoFullscreenManagerProxy::CleanupFullscreen(contextId), protectedThis->m_page->pageID());
476                 });
477             });
478         });
479     });
480 #endif
481 }
482     
483 void VideoFullscreenManager::didCleanupFullscreen(uint64_t contextId)
484 {
485     LOG(Fullscreen, "VideoFullscreenManager::didCleanupFullscreen(%p, %x)", this, contextId);
486
487     RefPtr<VideoFullscreenModelVideoElement> model;
488     RefPtr<VideoFullscreenInterfaceContext> interface;
489     std::tie(model, interface) = ensureModelAndInterface(contextId);
490
491     if (interface->layerHostingContext()) {
492         interface->layerHostingContext()->setRootLayer(nullptr);
493         interface->setLayerHostingContext(nullptr);
494     }
495
496     interface->setIsAnimating(false);
497     interface->setIsFullscreen(false);
498     HTMLMediaElementEnums::VideoFullscreenMode mode = interface->fullscreenMode();
499     bool standby = interface->fullscreenStandby();
500     bool targetIsFullscreen = interface->targetIsFullscreen();
501
502     model->setVideoFullscreenLayer(nil);
503     RefPtr<HTMLVideoElement> videoElement = model->videoElement();
504
505     interface->setFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
506     interface->setFullscreenStandby(false);
507     removeClientForContext(contextId);
508
509     if (!videoElement || !targetIsFullscreen)
510         return;
511
512     dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), videoElement, mode, standby] {
513         if (protectedThis->m_page)
514             protectedThis->enterVideoFullscreenForVideoElement(*videoElement, mode, standby);
515     });
516 }
517     
518 void VideoFullscreenManager::setVideoLayerGravityEnum(uint64_t contextId, unsigned gravity)
519 {
520     ensureModel(contextId).setVideoLayerGravity((VideoFullscreenModel::VideoGravity)gravity);
521 }
522     
523 void VideoFullscreenManager::fullscreenMayReturnToInline(uint64_t contextId, bool isPageVisible)
524 {
525     if (!m_page)
526         return;
527
528     auto& model = ensureModel(contextId);
529
530     if (!isPageVisible)
531         model.videoElement()->scrollIntoViewIfNotVisible(false);
532     m_page->send(Messages::VideoFullscreenManagerProxy::PreparedToReturnToInline(contextId, true, inlineVideoFrame(*model.videoElement())), m_page->pageID());
533 }
534     
535 void VideoFullscreenManager::setVideoLayerFrameFenced(uint64_t contextId, WebCore::FloatRect bounds, IPC::Attachment fencePort)
536 {
537     LOG(Fullscreen, "VideoFullscreenManager::setVideoLayerFrameFenced(%p, %x)", this, contextId);
538
539     RefPtr<VideoFullscreenModelVideoElement> model;
540     RefPtr<VideoFullscreenInterfaceContext> interface;
541     std::tie(model, interface) = ensureModelAndInterface(contextId);
542
543     if (std::isnan(bounds.x()) || std::isnan(bounds.y()) || std::isnan(bounds.width()) || std::isnan(bounds.height())) {
544         auto videoRect = inlineVideoFrame(*model->videoElement());
545         bounds = FloatRect(0, 0, videoRect.width(), videoRect.height());
546     }
547     
548     if (interface->layerHostingContext())
549         interface->layerHostingContext()->setFencePort(fencePort.port());
550     model->setVideoLayerFrame(bounds);
551     mach_port_deallocate(mach_task_self(), fencePort.port());
552 }
553
554 } // namespace WebKit
555
556 #endif // PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))