2 * Copyright (C) 2013 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
30 #import "WebVideoFullscreenControllerAVKit.h"
33 #import "MediaSelectionOption.h"
34 #import "PlaybackSessionInterfaceAVKit.h"
35 #import "PlaybackSessionModelMediaElement.h"
36 #import "TimeRanges.h"
37 #import "VideoFullscreenChangeObserver.h"
38 #import "VideoFullscreenInterfaceAVKit.h"
39 #import "VideoFullscreenModelVideoElement.h"
40 #import <QuartzCore/CoreAnimation.h>
41 #import <UIKit/UIView.h>
42 #import <WebCore/FrameView.h>
43 #import <WebCore/HTMLVideoElement.h>
44 #import <WebCore/RenderVideo.h>
45 #import <WebCore/WebCoreThreadRun.h>
46 #import <pal/spi/cocoa/QuartzCoreSPI.h>
47 #import <wtf/SoftLinking.h>
49 SOFT_LINK_FRAMEWORK(UIKit)
50 SOFT_LINK_CLASS(UIKit, UIView)
52 using namespace WebCore;
56 @implementation WebVideoFullscreenController
57 - (void)setVideoElement:(WebCore::HTMLVideoElement*)videoElement
59 UNUSED_PARAM(videoElement);
62 - (WebCore::HTMLVideoElement*)videoElement
67 - (void)enterFullscreen:(UIView *)view mode:(WebCore::HTMLMediaElementEnums::VideoFullscreenMode)mode
73 - (void)requestHideAndExitFullscreen
77 - (void)exitFullscreen
84 static IntRect elementRectInWindow(HTMLVideoElement* videoElement)
88 auto* renderer = videoElement->renderer();
89 auto* view = videoElement->document().view();
90 if (!renderer || !view)
92 return view->convertToContainingWindow(renderer->absoluteBoundingBoxRect());
95 class VideoFullscreenControllerContext;
97 @interface WebVideoFullscreenController (delegate)
98 -(void)didFinishFullscreen:(VideoFullscreenControllerContext*)context;
101 class VideoFullscreenControllerContext final
102 : private VideoFullscreenModel
103 , private VideoFullscreenModelClient
104 , private VideoFullscreenChangeObserver
105 , private PlaybackSessionModel
106 , private PlaybackSessionModelClient
107 , public ThreadSafeRefCounted<VideoFullscreenControllerContext> {
110 static Ref<VideoFullscreenControllerContext> create()
112 return adoptRef(*new VideoFullscreenControllerContext);
115 void setController(WebVideoFullscreenController* controller) { m_controller = controller; }
116 void setUpFullscreen(HTMLVideoElement&, UIView *, HTMLMediaElementEnums::VideoFullscreenMode);
117 void exitFullscreen();
118 void requestHideAndExitFullscreen();
122 VideoFullscreenControllerContext() { }
124 // VideoFullscreenChangeObserver
125 void requestUpdateInlineRect() override;
126 void requestVideoContentLayer() override;
127 void returnVideoContentLayer() override;
128 void didSetupFullscreen() override;
129 void didEnterFullscreen() override { }
130 void didExitFullscreen() override;
131 void didCleanupFullscreen() override;
132 void fullscreenMayReturnToInline() override;
134 // VideoFullscreenModelClient
135 void hasVideoChanged(bool) override;
136 void videoDimensionsChanged(const FloatSize&) override;
138 // PlaybackSessionModel
139 void addClient(PlaybackSessionModelClient&) override;
140 void removeClient(PlaybackSessionModelClient&) override;
141 void play() override;
142 void pause() override;
143 void togglePlayState() override;
144 void beginScrubbing() override;
145 void endScrubbing() override;
146 void seekToTime(double, double, double) override;
147 void fastSeek(double time) override;
148 void beginScanningForward() override;
149 void beginScanningBackward() override;
150 void endScanning() override;
151 void selectAudioMediaOption(uint64_t) override;
152 void selectLegibleMediaOption(uint64_t) override;
153 double duration() const override;
154 double playbackStartedTime() const override { return 0; }
155 double currentTime() const override;
156 double bufferedTime() const override;
157 bool isPlaying() const override;
158 bool isScrubbing() const override { return false; }
159 float playbackRate() const override;
160 Ref<TimeRanges> seekableRanges() const override;
161 double seekableTimeRangesLastModifiedTime() const override;
162 double liveUpdateInterval() const override;
163 bool canPlayFastReverse() const override;
164 Vector<MediaSelectionOption> audioMediaSelectionOptions() const override;
165 uint64_t audioMediaSelectedIndex() const override;
166 Vector<MediaSelectionOption> legibleMediaSelectionOptions() const override;
167 uint64_t legibleMediaSelectedIndex() const override;
168 bool externalPlaybackEnabled() const override;
169 ExternalPlaybackTargetType externalPlaybackTargetType() const override;
170 String externalPlaybackLocalizedDeviceName() const override;
171 bool wirelessVideoPlaybackDisabled() const override;
172 void togglePictureInPicture() override { }
173 void toggleMuted() override;
174 void setMuted(bool) final;
176 // PlaybackSessionModelClient
177 void durationChanged(double) override;
178 void currentTimeChanged(double currentTime, double anchorTime) override;
179 void bufferedTimeChanged(double) override;
180 void rateChanged(bool isPlaying, float playbackRate) override;
181 void seekableRangesChanged(const TimeRanges&, double lastModifiedTime, double liveUpdateInterval) override;
182 void canPlayFastReverseChanged(bool) override;
183 void audioMediaSelectionOptionsChanged(const Vector<MediaSelectionOption>& options, uint64_t selectedIndex) override;
184 void legibleMediaSelectionOptionsChanged(const Vector<MediaSelectionOption>& options, uint64_t selectedIndex) override;
185 void externalPlaybackChanged(bool enabled, PlaybackSessionModel::ExternalPlaybackTargetType, const String& localizedDeviceName) override;
186 void wirelessVideoPlaybackDisabledChanged(bool) override;
187 void mutedChanged(bool) override;
189 // VideoFullscreenModel
190 void addClient(VideoFullscreenModelClient&) override;
191 void removeClient(VideoFullscreenModelClient&) override;
192 void requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenMode, bool finishedWithMedia = false) override;
193 void setVideoLayerFrame(FloatRect) override;
194 void setVideoLayerGravity(VideoFullscreenModel::VideoGravity) override;
195 void fullscreenModeChanged(HTMLMediaElementEnums::VideoFullscreenMode) override;
196 bool isVisible() const override;
197 bool hasVideo() const override;
198 FloatSize videoDimensions() const override;
199 bool isMuted() const override;
201 HashSet<PlaybackSessionModelClient*> m_playbackClients;
202 HashSet<VideoFullscreenModelClient*> m_fullscreenClients;
203 RefPtr<VideoFullscreenInterfaceAVKit> m_interface;
204 RefPtr<VideoFullscreenModelVideoElement> m_fullscreenModel;
205 RefPtr<PlaybackSessionModelMediaElement> m_playbackModel;
206 RefPtr<HTMLVideoElement> m_videoElement;
207 RetainPtr<UIView> m_videoFullscreenView;
208 RetainPtr<WebVideoFullscreenController> m_controller;
211 #pragma mark VideoFullscreenChangeObserver
213 void VideoFullscreenControllerContext::requestUpdateInlineRect()
215 #if PLATFORM(IOS) && ENABLE(FULLSCREEN_API)
216 ASSERT(isUIThread());
217 WebThreadRun([protectedThis = makeRefPtr(this), this] () mutable {
218 IntRect clientRect = elementRectInWindow(m_videoElement.get());
219 dispatch_async(dispatch_get_main_queue(), [protectedThis = WTFMove(protectedThis), this, clientRect] {
220 m_interface->setInlineRect(clientRect, clientRect != IntRect(0, 0, 0, 0));
224 ASSERT_NOT_REACHED();
228 void VideoFullscreenControllerContext::requestVideoContentLayer()
230 #if PLATFORM(IOS) && ENABLE(FULLSCREEN_API)
231 ASSERT(isUIThread());
232 WebThreadRun([protectedThis = makeRefPtr(this), this, videoFullscreenLayer = retainPtr([m_videoFullscreenView layer])] () mutable {
233 [videoFullscreenLayer setBackgroundColor:cachedCGColor(WebCore::Color::transparent)];
234 m_fullscreenModel->setVideoFullscreenLayer(videoFullscreenLayer.get(), [protectedThis = WTFMove(protectedThis), this] () mutable {
235 dispatch_async(dispatch_get_main_queue(), [protectedThis = WTFMove(protectedThis), this] {
236 m_interface->setHasVideoContentLayer(true);
241 ASSERT_NOT_REACHED();
245 void VideoFullscreenControllerContext::returnVideoContentLayer()
247 #if PLATFORM(IOS) && ENABLE(FULLSCREEN_API)
248 ASSERT(isUIThread());
249 WebThreadRun([protectedThis = makeRefPtr(this), this, videoFullscreenLayer = retainPtr([m_videoFullscreenView layer])] () mutable {
250 [videoFullscreenLayer setBackgroundColor:cachedCGColor(WebCore::Color::transparent)];
251 m_fullscreenModel->setVideoFullscreenLayer(nil, [protectedThis = WTFMove(protectedThis), this] () mutable {
252 dispatch_async(dispatch_get_main_queue(), [protectedThis = WTFMove(protectedThis), this] {
253 m_interface->setHasVideoContentLayer(false);
258 ASSERT_NOT_REACHED();
262 void VideoFullscreenControllerContext::didSetupFullscreen()
264 ASSERT(isUIThread());
265 #if PLATFORM(IOS) && ENABLE(FULLSCREEN_API)
266 dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), this] {
267 m_interface->enterFullscreen();
270 WebThreadRun([protectedThis = makeRefPtr(this), this, videoFullscreenLayer = retainPtr([m_videoFullscreenView layer])] () mutable {
271 [videoFullscreenLayer setBackgroundColor:cachedCGColor(WebCore::Color::transparent)];
272 m_fullscreenModel->setVideoFullscreenLayer(videoFullscreenLayer.get(), [protectedThis = WTFMove(protectedThis), this] () mutable {
273 dispatch_async(dispatch_get_main_queue(), [protectedThis = WTFMove(protectedThis), this] {
274 m_interface->enterFullscreen();
281 void VideoFullscreenControllerContext::didExitFullscreen()
283 ASSERT(isUIThread());
284 #if PLATFORM(IOS) && ENABLE(FULLSCREEN_API)
285 dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), this] {
286 m_interface->cleanupFullscreen();
289 WebThreadRun([protectedThis = makeRefPtr(this), this] () mutable {
290 m_fullscreenModel->setVideoFullscreenLayer(nil, [protectedThis = WTFMove(protectedThis), this] () mutable {
291 dispatch_async(dispatch_get_main_queue(), [protectedThis = WTFMove(protectedThis), this] {
292 m_interface->cleanupFullscreen();
299 void VideoFullscreenControllerContext::didCleanupFullscreen()
301 ASSERT(isUIThread());
302 m_interface->setVideoFullscreenModel(nullptr);
303 m_interface->setVideoFullscreenChangeObserver(nullptr);
304 m_interface = nullptr;
305 m_videoFullscreenView = nil;
307 WebThreadRun([protectedThis = makeRefPtr(this), this] {
308 m_fullscreenModel->setVideoFullscreenLayer(nil);
309 m_fullscreenModel->setVideoElement(nullptr);
310 m_playbackModel->setMediaElement(nullptr);
311 m_fullscreenModel->removeClient(*this);
312 m_fullscreenModel = nullptr;
313 m_videoElement = nullptr;
315 [m_controller didFinishFullscreen:this];
319 void VideoFullscreenControllerContext::fullscreenMayReturnToInline()
321 ASSERT(isUIThread());
322 WebThreadRun([protectedThis = makeRefPtr(this), this] () mutable {
323 IntRect clientRect = elementRectInWindow(m_videoElement.get());
324 dispatch_async(dispatch_get_main_queue(), [protectedThis = WTFMove(protectedThis), this, clientRect] {
325 m_interface->preparedToReturnToInline(true, clientRect);
330 #pragma mark PlaybackSessionModelClient
332 void VideoFullscreenControllerContext::durationChanged(double duration)
334 if (WebThreadIsCurrent()) {
335 dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), duration] {
336 protectedThis->durationChanged(duration);
341 for (auto& client : m_playbackClients)
342 client->durationChanged(duration);
345 void VideoFullscreenControllerContext::currentTimeChanged(double currentTime, double anchorTime)
347 if (WebThreadIsCurrent()) {
348 dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), currentTime, anchorTime] {
349 protectedThis->currentTimeChanged(currentTime, anchorTime);
354 for (auto& client : m_playbackClients)
355 client->currentTimeChanged(currentTime, anchorTime);
358 void VideoFullscreenControllerContext::bufferedTimeChanged(double bufferedTime)
360 if (WebThreadIsCurrent()) {
361 dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), bufferedTime] {
362 protectedThis->bufferedTimeChanged(bufferedTime);
367 for (auto& client : m_playbackClients)
368 client->bufferedTimeChanged(bufferedTime);
371 void VideoFullscreenControllerContext::rateChanged(bool isPlaying, float playbackRate)
373 if (WebThreadIsCurrent()) {
374 dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), isPlaying, playbackRate] {
375 protectedThis->rateChanged(isPlaying, playbackRate);
380 for (auto& client : m_playbackClients)
381 client->rateChanged(isPlaying, playbackRate);
384 void VideoFullscreenControllerContext::hasVideoChanged(bool hasVideo)
386 if (WebThreadIsCurrent()) {
387 dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), hasVideo] {
388 protectedThis->hasVideoChanged(hasVideo);
393 for (auto& client : m_fullscreenClients)
394 client->hasVideoChanged(hasVideo);
397 void VideoFullscreenControllerContext::videoDimensionsChanged(const FloatSize& videoDimensions)
399 if (WebThreadIsCurrent()) {
400 dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), videoDimensions = videoDimensions] {
401 protectedThis->videoDimensionsChanged(videoDimensions);
406 for (auto& client : m_fullscreenClients)
407 client->videoDimensionsChanged(videoDimensions);
410 void VideoFullscreenControllerContext::seekableRangesChanged(const TimeRanges& timeRanges, double lastModifiedTime, double liveUpdateInterval)
412 if (WebThreadIsCurrent()) {
413 dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), platformTimeRanges = timeRanges.ranges(), lastModifiedTime, liveUpdateInterval] {
414 protectedThis->seekableRangesChanged(TimeRanges::create(platformTimeRanges), lastModifiedTime, liveUpdateInterval);
419 for (auto &client : m_playbackClients)
420 client->seekableRangesChanged(timeRanges, lastModifiedTime, liveUpdateInterval);
423 void VideoFullscreenControllerContext::canPlayFastReverseChanged(bool canPlayFastReverse)
425 if (WebThreadIsCurrent()) {
426 dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), canPlayFastReverse] {
427 protectedThis->canPlayFastReverseChanged(canPlayFastReverse);
432 for (auto &client : m_playbackClients)
433 client->canPlayFastReverseChanged(canPlayFastReverse);
436 static Vector<MediaSelectionOption> isolatedCopy(const Vector<MediaSelectionOption>& options)
438 Vector<MediaSelectionOption> optionsCopy;
439 optionsCopy.reserveInitialCapacity(options.size());
440 for (auto& option : options)
441 optionsCopy.uncheckedAppend({ option.displayName.isolatedCopy(), option.type });
445 void VideoFullscreenControllerContext::audioMediaSelectionOptionsChanged(const Vector<MediaSelectionOption>& options, uint64_t selectedIndex)
447 if (WebThreadIsCurrent()) {
448 dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), options = isolatedCopy(options), selectedIndex] {
449 protectedThis->audioMediaSelectionOptionsChanged(options, selectedIndex);
454 for (auto& client : m_playbackClients)
455 client->audioMediaSelectionOptionsChanged(options, selectedIndex);
458 void VideoFullscreenControllerContext::legibleMediaSelectionOptionsChanged(const Vector<MediaSelectionOption>& options, uint64_t selectedIndex)
460 if (WebThreadIsCurrent()) {
461 dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), options = isolatedCopy(options), selectedIndex] {
462 protectedThis->legibleMediaSelectionOptionsChanged(options, selectedIndex);
467 for (auto& client : m_playbackClients)
468 client->legibleMediaSelectionOptionsChanged(options, selectedIndex);
471 void VideoFullscreenControllerContext::externalPlaybackChanged(bool enabled, PlaybackSessionModel::ExternalPlaybackTargetType type, const String& localizedDeviceName)
473 if (WebThreadIsCurrent()) {
474 callOnMainThread([protectedThis = makeRef(*this), this, enabled, type, localizedDeviceName = localizedDeviceName.isolatedCopy()] {
475 for (auto& client : m_playbackClients)
476 client->externalPlaybackChanged(enabled, type, localizedDeviceName);
481 for (auto& client : m_playbackClients)
482 client->externalPlaybackChanged(enabled, type, localizedDeviceName);
485 void VideoFullscreenControllerContext::wirelessVideoPlaybackDisabledChanged(bool disabled)
487 if (WebThreadIsCurrent()) {
488 dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), disabled] {
489 protectedThis->wirelessVideoPlaybackDisabledChanged(disabled);
494 for (auto& client : m_playbackClients)
495 client->wirelessVideoPlaybackDisabledChanged(disabled);
498 void VideoFullscreenControllerContext::mutedChanged(bool muted)
500 if (WebThreadIsCurrent()) {
501 dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), muted] {
502 protectedThis->mutedChanged(muted);
507 for (auto& client : m_playbackClients)
508 client->mutedChanged(muted);
511 #pragma mark VideoFullscreenModel
513 void VideoFullscreenControllerContext::addClient(VideoFullscreenModelClient& client)
515 ASSERT(!m_fullscreenClients.contains(&client));
516 m_fullscreenClients.add(&client);
519 void VideoFullscreenControllerContext::removeClient(VideoFullscreenModelClient& client)
521 ASSERT(m_fullscreenClients.contains(&client));
522 m_fullscreenClients.remove(&client);
525 void VideoFullscreenControllerContext::requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenMode mode, bool finishedWithMedia)
527 ASSERT(isUIThread());
528 WebThreadRun([protectedThis = makeRefPtr(this), this, mode, finishedWithMedia] {
529 if (m_fullscreenModel)
530 m_fullscreenModel->requestFullscreenMode(mode, finishedWithMedia);
534 void VideoFullscreenControllerContext::setVideoLayerFrame(FloatRect frame)
536 ASSERT(isUIThread());
537 RetainPtr<CALayer> videoFullscreenLayer = [m_videoFullscreenView layer];
538 [videoFullscreenLayer setSublayerTransform:[videoFullscreenLayer transform]];
540 dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), this, frame, videoFullscreenLayer = WTFMove(videoFullscreenLayer)] () mutable {
541 WebThreadRun([protectedThis = WTFMove(protectedThis), this, frame, videoFullscreenLayer = WTFMove(videoFullscreenLayer)] {
542 [CATransaction begin];
543 [CATransaction setDisableActions:YES];
544 [CATransaction setAnimationDuration:0];
546 [videoFullscreenLayer setSublayerTransform:CATransform3DIdentity];
548 if (m_fullscreenModel)
549 m_fullscreenModel->setVideoLayerFrame(frame);
550 [CATransaction commit];
555 void VideoFullscreenControllerContext::setVideoLayerGravity(VideoFullscreenModel::VideoGravity videoGravity)
557 ASSERT(isUIThread());
558 WebThreadRun([protectedThis = makeRefPtr(this), this, videoGravity] {
559 if (m_fullscreenModel)
560 m_fullscreenModel->setVideoLayerGravity(videoGravity);
564 void VideoFullscreenControllerContext::fullscreenModeChanged(HTMLMediaElementEnums::VideoFullscreenMode mode)
566 ASSERT(isUIThread());
567 WebThreadRun([protectedThis = makeRefPtr(this), this, mode] {
568 if (m_fullscreenModel)
569 m_fullscreenModel->fullscreenModeChanged(mode);
573 bool VideoFullscreenControllerContext::isVisible() const
575 ASSERT(isUIThread());
576 return m_fullscreenModel ? m_fullscreenModel->isVisible() : false;
579 bool VideoFullscreenControllerContext::hasVideo() const
581 ASSERT(isUIThread());
582 return m_fullscreenModel ? m_fullscreenModel->hasVideo() : false;
585 bool VideoFullscreenControllerContext::isMuted() const
587 ASSERT(isUIThread());
588 return m_playbackModel ? m_playbackModel->isMuted() : false;
591 FloatSize VideoFullscreenControllerContext::videoDimensions() const
593 ASSERT(isUIThread());
594 return m_fullscreenModel ? m_fullscreenModel->videoDimensions() : FloatSize();
597 #pragma mark - PlaybackSessionModel
599 void VideoFullscreenControllerContext::addClient(PlaybackSessionModelClient& client)
601 ASSERT(!m_playbackClients.contains(&client));
602 m_playbackClients.add(&client);
605 void VideoFullscreenControllerContext::removeClient(PlaybackSessionModelClient& client)
607 ASSERT(m_playbackClients.contains(&client));
608 m_playbackClients.remove(&client);
611 void VideoFullscreenControllerContext::play()
613 ASSERT(isUIThread());
614 WebThreadRun([protectedThis = makeRefPtr(this), this] {
616 m_playbackModel->play();
620 void VideoFullscreenControllerContext::pause()
622 ASSERT(isUIThread());
623 WebThreadRun([protectedThis = makeRefPtr(this), this] {
625 m_playbackModel->pause();
629 void VideoFullscreenControllerContext::togglePlayState()
631 ASSERT(isUIThread());
632 WebThreadRun([protectedThis = makeRefPtr(this), this] {
634 m_playbackModel->togglePlayState();
638 void VideoFullscreenControllerContext::toggleMuted()
640 ASSERT(isUIThread());
641 WebThreadRun([protectedThis = makeRefPtr(this), this] {
643 m_playbackModel->toggleMuted();
647 void VideoFullscreenControllerContext::setMuted(bool muted)
649 ASSERT(isUIThread());
650 WebThreadRun([protectedThis = makeRefPtr(this), this, muted] {
652 m_playbackModel->setMuted(muted);
656 void VideoFullscreenControllerContext::beginScrubbing()
658 ASSERT(isUIThread());
659 WebThreadRun([protectedThis = makeRefPtr(this), this] {
661 m_playbackModel->beginScrubbing();
665 void VideoFullscreenControllerContext::endScrubbing()
667 ASSERT(isUIThread());
668 WebThreadRun([protectedThis = makeRefPtr(this), this] {
670 m_playbackModel->endScrubbing();
674 void VideoFullscreenControllerContext::seekToTime(double time, double toleranceBefore, double toleranceAfter)
676 ASSERT(isUIThread());
677 WebThreadRun([protectedThis = makeRefPtr(this), this, time, toleranceBefore, toleranceAfter] {
679 m_playbackModel->seekToTime(time, toleranceBefore, toleranceAfter);
683 void VideoFullscreenControllerContext::fastSeek(double time)
685 ASSERT(isUIThread());
686 WebThreadRun([protectedThis = makeRefPtr(this), this, time] {
688 m_playbackModel->fastSeek(time);
692 void VideoFullscreenControllerContext::beginScanningForward()
694 ASSERT(isUIThread());
695 WebThreadRun([protectedThis = makeRefPtr(this), this] {
697 m_playbackModel->beginScanningForward();
701 void VideoFullscreenControllerContext::beginScanningBackward()
703 ASSERT(isUIThread());
704 WebThreadRun([protectedThis = makeRefPtr(this), this] {
706 m_playbackModel->beginScanningBackward();
710 void VideoFullscreenControllerContext::endScanning()
712 ASSERT(isUIThread());
713 WebThreadRun([protectedThis = makeRefPtr(this), this] {
715 m_playbackModel->endScanning();
719 void VideoFullscreenControllerContext::selectAudioMediaOption(uint64_t index)
721 ASSERT(isUIThread());
722 WebThreadRun([protectedThis = makeRefPtr(this), this, index] {
724 m_playbackModel->selectAudioMediaOption(index);
728 void VideoFullscreenControllerContext::selectLegibleMediaOption(uint64_t index)
730 ASSERT(isUIThread());
731 WebThreadRun([protectedThis = makeRefPtr(this), this, index] {
733 m_playbackModel->selectLegibleMediaOption(index);
737 double VideoFullscreenControllerContext::duration() const
739 ASSERT(isUIThread());
740 return m_playbackModel ? m_playbackModel->duration() : 0;
743 double VideoFullscreenControllerContext::currentTime() const
745 ASSERT(isUIThread());
746 return m_playbackModel ? m_playbackModel->currentTime() : 0;
749 double VideoFullscreenControllerContext::bufferedTime() const
751 ASSERT(isUIThread());
752 return m_playbackModel ? m_playbackModel->bufferedTime() : 0;
755 bool VideoFullscreenControllerContext::isPlaying() const
757 ASSERT(isUIThread());
758 return m_playbackModel ? m_playbackModel->isPlaying() : false;
761 float VideoFullscreenControllerContext::playbackRate() const
763 ASSERT(isUIThread());
764 return m_playbackModel ? m_playbackModel->playbackRate() : 0;
767 Ref<TimeRanges> VideoFullscreenControllerContext::seekableRanges() const
769 ASSERT(isUIThread());
770 return m_playbackModel ? m_playbackModel->seekableRanges() : TimeRanges::create();
773 double VideoFullscreenControllerContext::seekableTimeRangesLastModifiedTime() const
775 ASSERT(isUIThread());
776 return m_playbackModel ? m_playbackModel->seekableTimeRangesLastModifiedTime() : 0;
779 double VideoFullscreenControllerContext::liveUpdateInterval() const
781 ASSERT(isUIThread());
782 return m_playbackModel ? m_playbackModel->liveUpdateInterval() : 0;
785 bool VideoFullscreenControllerContext::canPlayFastReverse() const
787 ASSERT(isUIThread());
788 return m_playbackModel ? m_playbackModel->canPlayFastReverse() : false;
791 Vector<MediaSelectionOption> VideoFullscreenControllerContext::audioMediaSelectionOptions() const
793 ASSERT(isUIThread());
795 return m_playbackModel->audioMediaSelectionOptions();
799 uint64_t VideoFullscreenControllerContext::audioMediaSelectedIndex() const
801 ASSERT(isUIThread());
802 return m_playbackModel ? m_playbackModel->audioMediaSelectedIndex() : -1;
805 Vector<MediaSelectionOption> VideoFullscreenControllerContext::legibleMediaSelectionOptions() const
807 ASSERT(isUIThread());
809 return m_playbackModel->legibleMediaSelectionOptions();
813 uint64_t VideoFullscreenControllerContext::legibleMediaSelectedIndex() const
815 ASSERT(isUIThread());
816 return m_playbackModel ? m_playbackModel->legibleMediaSelectedIndex() : -1;
819 bool VideoFullscreenControllerContext::externalPlaybackEnabled() const
821 ASSERT(isUIThread());
822 return m_playbackModel ? m_playbackModel->externalPlaybackEnabled() : false;
825 PlaybackSessionModel::ExternalPlaybackTargetType VideoFullscreenControllerContext::externalPlaybackTargetType() const
827 ASSERT(isUIThread());
828 return m_playbackModel ? m_playbackModel->externalPlaybackTargetType() : TargetTypeNone;
831 String VideoFullscreenControllerContext::externalPlaybackLocalizedDeviceName() const
833 ASSERT(isUIThread());
834 return m_playbackModel ? m_playbackModel->externalPlaybackLocalizedDeviceName() : String();
837 bool VideoFullscreenControllerContext::wirelessVideoPlaybackDisabled() const
839 ASSERT(isUIThread());
840 return m_playbackModel ? m_playbackModel->wirelessVideoPlaybackDisabled() : true;
845 void VideoFullscreenControllerContext::setUpFullscreen(HTMLVideoElement& videoElement, UIView *view, HTMLMediaElementEnums::VideoFullscreenMode mode)
847 ASSERT(isMainThread());
848 RetainPtr<UIView> viewRef = view;
849 m_videoElement = &videoElement;
850 m_playbackModel = PlaybackSessionModelMediaElement::create();
851 m_playbackModel->addClient(*this);
852 m_playbackModel->setMediaElement(m_videoElement.get());
854 m_fullscreenModel = VideoFullscreenModelVideoElement::create();
855 m_fullscreenModel->addClient(*this);
856 m_fullscreenModel->setVideoElement(m_videoElement.get());
858 bool allowsPictureInPicture = m_videoElement->webkitSupportsPresentationMode(HTMLVideoElement::VideoPresentationMode::PictureInPicture);
860 IntRect videoElementClientRect = elementRectInWindow(m_videoElement.get());
861 FloatRect videoLayerFrame = FloatRect(FloatPoint(), videoElementClientRect.size());
862 m_fullscreenModel->setVideoLayerFrame(videoLayerFrame);
864 dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), this, videoElementClientRect, viewRef, mode, allowsPictureInPicture] {
865 ASSERT(isUIThread());
867 Ref<PlaybackSessionInterfaceAVKit> sessionInterface = PlaybackSessionInterfaceAVKit::create(*this);
868 m_interface = VideoFullscreenInterfaceAVKit::create(sessionInterface.get());
869 m_interface->setVideoFullscreenChangeObserver(this);
870 m_interface->setVideoFullscreenModel(this);
871 m_interface->setVideoFullscreenChangeObserver(this);
873 m_videoFullscreenView = adoptNS([allocUIViewInstance() init]);
875 m_interface->setupFullscreen(*m_videoFullscreenView.get(), videoElementClientRect, viewRef.get(), mode, allowsPictureInPicture, false);
879 void VideoFullscreenControllerContext::exitFullscreen()
881 ASSERT(WebThreadIsCurrent() || isMainThread());
882 IntRect clientRect = elementRectInWindow(m_videoElement.get());
883 dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), this, clientRect] {
884 ASSERT(isUIThread());
885 m_interface->exitFullscreen(clientRect);
889 void VideoFullscreenControllerContext::requestHideAndExitFullscreen()
891 ASSERT(isUIThread());
892 m_interface->requestHideAndExitFullscreen();
895 @implementation WebVideoFullscreenController {
896 RefPtr<VideoFullscreenControllerContext> _context;
897 RefPtr<HTMLVideoElement> _videoElement;
902 if (!(self = [super init]))
908 - (void)setVideoElement:(HTMLVideoElement*)videoElement
910 _videoElement = videoElement;
913 - (HTMLVideoElement*)videoElement
915 return _videoElement.get();
918 - (void)enterFullscreen:(UIView *)view mode:(HTMLMediaElementEnums::VideoFullscreenMode)mode
920 ASSERT(isMainThread());
921 _context = VideoFullscreenControllerContext::create();
922 _context->setController(self);
923 _context->setUpFullscreen(*_videoElement.get(), view, mode);
926 - (void)exitFullscreen
928 ASSERT(WebThreadIsCurrent() || isMainThread());
929 _context->exitFullscreen();
932 - (void)requestHideAndExitFullscreen
934 ASSERT(isUIThread());
936 _context->requestHideAndExitFullscreen();
939 - (void)didFinishFullscreen:(VideoFullscreenControllerContext*)context
941 ASSERT(WebThreadIsCurrent());
942 ASSERT_UNUSED(context, context == _context);
943 [[self retain] autorelease]; // retain self before breaking a retain cycle.
944 _context->setController(nil);
946 _videoElement = nullptr;
951 #endif // !HAVE(AVKIT)
953 #endif // PLATFORM(IOS)