Touching HTMLMediaElement.h or MediaPlayer.h causes a world rebuild.
[WebKit-https.git] / Source / WebKit2 / UIProcess / ios / WebVideoFullscreenManagerProxy.mm
1 /*
2  * Copyright (C) 2014 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
26 #import "config.h"
27 #import "WebVideoFullscreenManagerProxy.h"
28
29 #if PLATFORM(IOS)
30
31 #import "RemoteLayerTreeDrawingAreaProxy.h"
32 #import "UIKitSPI.h"
33 #import "WebPageProxy.h"
34 #import "WebProcessProxy.h"
35 #import "WebVideoFullscreenManagerMessages.h"
36 #import "WebVideoFullscreenManagerProxyMessages.h"
37 #import <QuartzCore/CoreAnimation.h>
38 #import <WebCore/TimeRanges.h>
39 #import <WebKitSystemInterface.h>
40
41 #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 90000
42 #import "BackBoardServicesSPI.h"
43 #endif
44
45 using namespace WebCore;
46
47 namespace WebKit {
48
49 #if __IPHONE_OS_VERSION_MIN_REQUIRED < 90000 || !HAVE(AVKIT)
50
51 PassRefPtr<WebVideoFullscreenManagerProxy> WebVideoFullscreenManagerProxy::create(WebPageProxy&)
52 {
53     return nullptr;
54 }
55
56 void WebVideoFullscreenManagerProxy::invalidate()
57 {
58 }
59
60 bool WebVideoFullscreenManagerProxy::hasMode(HTMLMediaElementEnums::VideoFullscreenMode) const
61 {
62     return false;
63 }
64
65 bool WebVideoFullscreenManagerProxy::mayAutomaticallyShowVideoOptimized() const
66 {
67     return false;
68 }
69
70 void WebVideoFullscreenManagerProxy::requestHideAndExitFullscreen()
71 {
72
73 }
74 #else
75
76 #pragma mark - WebVideoFullscreenModelContext
77
78 void WebVideoFullscreenModelContext::play()
79 {
80     if (m_manager)
81         m_manager->play(m_contextId);
82 }
83
84 void WebVideoFullscreenModelContext::pause()
85 {
86     if (m_manager)
87         m_manager->pause(m_contextId);
88 }
89
90 void WebVideoFullscreenModelContext::togglePlayState()
91 {
92     if (m_manager)
93         m_manager->togglePlayState(m_contextId);
94 }
95
96 void WebVideoFullscreenModelContext::beginScrubbing()
97 {
98     if (m_manager)
99         m_manager->beginScrubbing(m_contextId);
100 }
101
102 void WebVideoFullscreenModelContext::endScrubbing()
103 {
104     if (m_manager)
105         m_manager->endScrubbing(m_contextId);
106 }
107
108 void WebVideoFullscreenModelContext::seekToTime(double time)
109 {
110     if (m_manager)
111         m_manager->seekToTime(m_contextId, time);
112 }
113
114 void WebVideoFullscreenModelContext::fastSeek(double time)
115 {
116     if (m_manager)
117         m_manager->fastSeek(m_contextId, time);
118 }
119
120 void WebVideoFullscreenModelContext::beginScanningForward()
121 {
122     if (m_manager)
123         m_manager->beginScanningForward(m_contextId);
124 }
125
126 void WebVideoFullscreenModelContext::beginScanningBackward()
127 {
128     if (m_manager)
129         m_manager->beginScanningBackward(m_contextId);
130 }
131
132 void WebVideoFullscreenModelContext::endScanning()
133 {
134     if (m_manager)
135         m_manager->endScanning(m_contextId);
136 }
137
138 void WebVideoFullscreenModelContext::requestExitFullscreen()
139 {
140     if (m_manager)
141         m_manager->requestExitFullscreen(m_contextId);
142 }
143
144 void WebVideoFullscreenModelContext::setVideoLayerFrame(WebCore::FloatRect frame)
145 {
146     m_videoLayerFrame = frame;
147     if (m_manager)
148         m_manager->setVideoLayerFrame(m_contextId, frame);
149 }
150
151 WebCore::FloatRect WebVideoFullscreenModelContext::videoLayerFrame() const
152 {
153     return m_videoLayerFrame;
154 }
155
156 void WebVideoFullscreenModelContext::setVideoLayerGravity(WebCore::WebVideoFullscreenModel::VideoGravity gravity)
157 {
158     m_videoLayerGravity = gravity;
159     if (m_manager)
160         m_manager->setVideoLayerGravity(m_contextId, gravity);
161 }
162
163 WebCore::WebVideoFullscreenModel::VideoGravity WebVideoFullscreenModelContext::videoLayerGravity() const
164 {
165     return m_videoLayerGravity;
166 }
167
168 void WebVideoFullscreenModelContext::selectAudioMediaOption(uint64_t optionId)
169 {
170     if (m_manager)
171         m_manager->selectAudioMediaOption(m_contextId, optionId);
172 }
173
174 void WebVideoFullscreenModelContext::selectLegibleMediaOption(uint64_t optionId)
175 {
176     if (m_manager)
177         m_manager->selectLegibleMediaOption(m_contextId, optionId);
178 }
179
180 void WebVideoFullscreenModelContext::fullscreenModeChanged(WebCore::HTMLMediaElementEnums::VideoFullscreenMode mode)
181 {
182     if (m_manager)
183         m_manager->fullscreenModeChanged(m_contextId, mode);
184 }
185
186 void WebVideoFullscreenModelContext::didSetupFullscreen()
187 {
188     if (m_manager)
189         m_manager->didSetupFullscreen(m_contextId);
190 }
191
192 void WebVideoFullscreenModelContext::didEnterFullscreen()
193 {
194     if (m_manager)
195         m_manager->didEnterFullscreen(m_contextId);
196 }
197
198 void WebVideoFullscreenModelContext::didExitFullscreen()
199 {
200     if (m_manager)
201         m_manager->didExitFullscreen(m_contextId);
202 }
203
204 void WebVideoFullscreenModelContext::didCleanupFullscreen()
205 {
206     if (m_manager)
207         m_manager->didCleanupFullscreen(m_contextId);
208 }
209
210 void WebVideoFullscreenModelContext::fullscreenMayReturnToInline()
211 {
212     if (m_manager)
213         m_manager->fullscreenMayReturnToInline(m_contextId);
214 }
215
216 #pragma mark - WebVideoFullscreenManagerProxy
217
218 PassRefPtr<WebVideoFullscreenManagerProxy> WebVideoFullscreenManagerProxy::create(WebPageProxy& page)
219 {
220     return adoptRef(new WebVideoFullscreenManagerProxy(page));
221 }
222
223 WebVideoFullscreenManagerProxy::WebVideoFullscreenManagerProxy(WebPageProxy& page)
224     : m_page(&page)
225 {
226     m_page->process().addMessageReceiver(Messages::WebVideoFullscreenManagerProxy::messageReceiverName(), m_page->pageID(), *this);
227 }
228
229 WebVideoFullscreenManagerProxy::~WebVideoFullscreenManagerProxy()
230 {
231     if (!m_page)
232         return;
233     invalidate();
234 }
235
236 void WebVideoFullscreenManagerProxy::invalidate()
237 {
238     m_page->process().removeMessageReceiver(Messages::WebVideoFullscreenManagerProxy::messageReceiverName(), m_page->pageID());
239     m_page = nullptr;
240
241     for (auto& tuple : m_contextMap.values()) {
242         RefPtr<WebVideoFullscreenModelContext> model;
243         RefPtr<WebCore::WebVideoFullscreenInterfaceAVKit> interface;
244         std::tie(model, interface) = tuple;
245
246         interface->invalidate();
247         [model->layerHost() removeFromSuperlayer];
248         model->setLayerHost(nullptr);
249     }
250
251     m_contextMap.clear();
252 }
253
254 void WebVideoFullscreenManagerProxy::requestHideAndExitFullscreen()
255 {
256     for (auto& tuple : m_contextMap.values())
257         std::get<1>(tuple)->requestHideAndExitFullscreen();
258 }
259
260 bool WebVideoFullscreenManagerProxy::hasMode(HTMLMediaElementEnums::VideoFullscreenMode mode) const
261 {
262     for (auto& tuple : m_contextMap.values()) {
263         if (std::get<1>(tuple)->hasMode(mode))
264             return true;
265     }
266     return false;
267 }
268
269 bool WebVideoFullscreenManagerProxy::mayAutomaticallyShowVideoOptimized() const
270 {
271     for (auto& tuple : m_contextMap.values()) {
272         if (std::get<1>(tuple)->mayAutomaticallyShowVideoOptimized())
273             return true;
274     }
275     return false;
276 }
277
278 WebVideoFullscreenManagerProxy::ModelInterfaceTuple WebVideoFullscreenManagerProxy::createModelAndInterface(uint64_t contextId)
279 {
280     Ref<WebVideoFullscreenModelContext> model = WebVideoFullscreenModelContext::create(*this, contextId);
281     Ref<WebCore::WebVideoFullscreenInterfaceAVKit> interface = WebVideoFullscreenInterfaceAVKit::create();
282
283     interface->setWebVideoFullscreenModel(&model.get());
284     interface->setWebVideoFullscreenChangeObserver(&model.get());
285
286     return std::make_tuple(WTF::move(model), WTF::move(interface));
287 }
288
289 WebVideoFullscreenManagerProxy::ModelInterfaceTuple& WebVideoFullscreenManagerProxy::ensureModelAndInterface(uint64_t contextId)
290 {
291     auto addResult = m_contextMap.add(contextId, ModelInterfaceTuple());
292     if (addResult.isNewEntry)
293         addResult.iterator->value = createModelAndInterface(contextId);
294     return addResult.iterator->value;
295 }
296
297 WebVideoFullscreenModelContext& WebVideoFullscreenManagerProxy::ensureModel(uint64_t contextId)
298 {
299     return *std::get<0>(ensureModelAndInterface(contextId));
300 }
301
302 WebCore::WebVideoFullscreenInterfaceAVKit& WebVideoFullscreenManagerProxy::ensureInterface(uint64_t contextId)
303 {
304     return *std::get<1>(ensureModelAndInterface(contextId));
305 }
306
307 #pragma mark Messages from WebVideoFullscreenManager
308
309 void WebVideoFullscreenManagerProxy::setupFullscreenWithID(uint64_t contextId, uint32_t videoLayerID, const WebCore::IntRect& initialRect, float hostingDeviceScaleFactor, HTMLMediaElementEnums::VideoFullscreenMode videoFullscreenMode, bool allowOptimizedFullscreen)
310 {
311     ASSERT(videoLayerID);
312     RefPtr<WebVideoFullscreenModelContext> model;
313     RefPtr<WebCore::WebVideoFullscreenInterfaceAVKit> interface;
314
315     std::tie(model, interface) = ensureModelAndInterface(contextId);
316
317     model->setInitialVideoLayerFrame(initialRect);
318     model->setLayerHost(WKMakeRenderLayer(videoLayerID));
319     if (hostingDeviceScaleFactor != 1) {
320         // Invert the scale transform added in the WebProcess to fix <rdar://problem/18316542>.
321         float inverseScale = 1 / hostingDeviceScaleFactor;
322         [model->layerHost() setTransform:CATransform3DMakeScale(inverseScale, inverseScale, 1)];
323     }
324
325     UIView *parentView = downcast<RemoteLayerTreeDrawingAreaProxy>(*m_page->drawingArea()).remoteLayerTreeHost().rootLayer();
326     interface->setupFullscreen(*model->layerHost(), initialRect, parentView, videoFullscreenMode, allowOptimizedFullscreen);
327 }
328
329 void WebVideoFullscreenManagerProxy::resetMediaState(uint64_t contextId)
330 {
331     ensureInterface(contextId).resetMediaState();
332 }
333
334 void WebVideoFullscreenManagerProxy::setCurrentTime(uint64_t contextId, double currentTime, double hostTime)
335 {
336     ensureInterface(contextId).setCurrentTime(currentTime, hostTime);
337 }
338
339 void WebVideoFullscreenManagerProxy::setBufferedTime(uint64_t contextId, double bufferedTime)
340 {
341     ensureInterface(contextId).setBufferedTime(bufferedTime);
342 }
343
344 void WebVideoFullscreenManagerProxy::setVideoDimensions(uint64_t contextId, bool hasVideo, unsigned width, unsigned height)
345 {
346     ensureInterface(contextId).setVideoDimensions(hasVideo, width, height);
347 }
348
349 void WebVideoFullscreenManagerProxy::setSeekableRangesVector(uint64_t contextId, Vector<std::pair<double, double>> ranges)
350 {
351     RefPtr<TimeRanges> timeRanges = TimeRanges::create();
352     for (const auto& range : ranges)
353     {
354         ASSERT(isfinite(range.first));
355         ASSERT(isfinite(range.second));
356         ASSERT(range.second >= range.first);
357         timeRanges->add(range.first, range.second);
358     }
359
360     ensureInterface(contextId).setSeekableRanges(*timeRanges);
361 }
362
363 void WebVideoFullscreenManagerProxy::setCanPlayFastReverse(uint64_t contextId, bool value)
364 {
365     ensureInterface(contextId).setCanPlayFastReverse(value);
366 }
367
368 void WebVideoFullscreenManagerProxy::setAudioMediaSelectionOptions(uint64_t contextId, Vector<String> options, uint64_t selectedIndex)
369 {
370     ensureInterface(contextId).setAudioMediaSelectionOptions(options, selectedIndex);
371 }
372
373 void WebVideoFullscreenManagerProxy::setLegibleMediaSelectionOptions(uint64_t contextId, Vector<String> options, uint64_t selectedIndex)
374 {
375     ensureInterface(contextId).setLegibleMediaSelectionOptions(options, selectedIndex);
376 }
377
378 void WebVideoFullscreenManagerProxy::setExternalPlaybackProperties(uint64_t contextId, bool enabled, uint32_t targetType, String localizedDeviceName)
379 {
380     WebVideoFullscreenInterface::ExternalPlaybackTargetType type = static_cast<WebVideoFullscreenInterface::ExternalPlaybackTargetType>(targetType);
381     ASSERT(type == WebVideoFullscreenInterface::TargetTypeAirPlay || type == WebVideoFullscreenInterface::TargetTypeTVOut || type == WebVideoFullscreenInterface::TargetTypeNone);
382     
383     ensureInterface(contextId).setExternalPlayback(enabled, type, localizedDeviceName);
384 }
385
386 void WebVideoFullscreenManagerProxy::setDuration(uint64_t contextId, double duration)
387 {
388     ensureInterface(contextId).setDuration(duration);
389 }
390
391 void WebVideoFullscreenManagerProxy::setRate(uint64_t contextId, bool isPlaying, double rate)
392 {
393     ensureInterface(contextId).setRate(isPlaying, rate);
394 }
395
396 void WebVideoFullscreenManagerProxy::enterFullscreen(uint64_t contextId)
397 {
398     auto& interface = ensureInterface(contextId);
399     interface.enterFullscreen();
400
401     // Only one context can be in a given full screen mode at a time:
402     for (auto& contextPair : m_contextMap) {
403         auto& otherContextId = contextPair.key;
404         if (contextId == otherContextId)
405             continue;
406
407         auto& otherInterface = std::get<1>(contextPair.value);
408         if (otherInterface->hasMode(interface.mode()))
409             otherInterface->requestHideAndExitFullscreen();
410     }
411 }
412
413 void WebVideoFullscreenManagerProxy::exitFullscreen(uint64_t contextId, WebCore::IntRect finalRect)
414 {
415     ensureInterface(contextId).exitFullscreen(finalRect);
416 }
417
418 void WebVideoFullscreenManagerProxy::cleanupFullscreen(uint64_t contextId)
419 {
420     ensureInterface(contextId).cleanupFullscreen();
421 }
422
423 void WebVideoFullscreenManagerProxy::preparedToReturnToInline(uint64_t contextId, bool visible, WebCore::IntRect inlineRect)
424 {
425     m_page->fullscreenMayReturnToInline();
426
427     ensureInterface(contextId).preparedToReturnToInline(visible, inlineRect);
428 }
429
430 #pragma mark Messages to WebVideoFullscreenManager
431
432 void WebVideoFullscreenManagerProxy::play(uint64_t contextId)
433 {
434     m_page->send(Messages::WebVideoFullscreenManager::Play(contextId), m_page->pageID());
435 }
436
437 void WebVideoFullscreenManagerProxy::pause(uint64_t contextId)
438 {
439     m_page->send(Messages::WebVideoFullscreenManager::Pause(contextId), m_page->pageID());
440 }
441
442 void WebVideoFullscreenManagerProxy::togglePlayState(uint64_t contextId)
443 {
444     m_page->send(Messages::WebVideoFullscreenManager::TogglePlayState(contextId), m_page->pageID());
445 }
446
447 void WebVideoFullscreenManagerProxy::beginScrubbing(uint64_t contextId)
448 {
449     m_page->send(Messages::WebVideoFullscreenManager::BeginScrubbing(contextId), m_page->pageID());
450 }
451
452 void WebVideoFullscreenManagerProxy::endScrubbing(uint64_t contextId)
453 {
454     m_page->send(Messages::WebVideoFullscreenManager::EndScrubbing(contextId), m_page->pageID());
455 }
456
457 void WebVideoFullscreenManagerProxy::seekToTime(uint64_t contextId, double time)
458 {
459     m_page->send(Messages::WebVideoFullscreenManager::SeekToTime(contextId, time), m_page->pageID());
460 }
461
462 void WebVideoFullscreenManagerProxy::fastSeek(uint64_t contextId, double time)
463 {
464     m_page->send(Messages::WebVideoFullscreenManager::FastSeek(contextId, time), m_page->pageID());
465 }
466
467 void WebVideoFullscreenManagerProxy::beginScanningForward(uint64_t contextId)
468 {
469     m_page->send(Messages::WebVideoFullscreenManager::BeginScanningForward(contextId), m_page->pageID());
470 }
471
472 void WebVideoFullscreenManagerProxy::beginScanningBackward(uint64_t contextId)
473 {
474     m_page->send(Messages::WebVideoFullscreenManager::BeginScanningBackward(contextId), m_page->pageID());
475 }
476
477 void WebVideoFullscreenManagerProxy::endScanning(uint64_t contextId)
478 {
479     m_page->send(Messages::WebVideoFullscreenManager::EndScanning(contextId), m_page->pageID());
480 }
481
482 void WebVideoFullscreenManagerProxy::requestExitFullscreen(uint64_t contextId)
483 {
484     m_page->send(Messages::WebVideoFullscreenManager::RequestExitFullscreen(contextId), m_page->pageID());
485 }
486
487 void WebVideoFullscreenManagerProxy::didSetupFullscreen(uint64_t contextId)
488 {
489     m_page->send(Messages::WebVideoFullscreenManager::DidSetupFullscreen(contextId), m_page->pageID());
490 }
491
492 void WebVideoFullscreenManagerProxy::didExitFullscreen(uint64_t contextId)
493 {
494     m_page->send(Messages::WebVideoFullscreenManager::DidExitFullscreen(contextId), m_page->pageID());
495     m_page->didExitFullscreen();
496 }
497
498 void WebVideoFullscreenManagerProxy::didEnterFullscreen(uint64_t contextId)
499 {
500     m_page->send(Messages::WebVideoFullscreenManager::DidEnterFullscreen(contextId), m_page->pageID());
501     m_page->didEnterFullscreen();
502 }
503
504 void WebVideoFullscreenManagerProxy::didCleanupFullscreen(uint64_t contextId)
505 {
506     auto& model = ensureModel(contextId);
507
508     [CATransaction flush];
509     [model.layerHost() removeFromSuperlayer];
510     model.setLayerHost(nullptr);
511     m_page->send(Messages::WebVideoFullscreenManager::DidCleanupFullscreen(contextId), m_page->pageID());
512
513     m_contextMap.remove(contextId);
514 }
515
516 void WebVideoFullscreenManagerProxy::setVideoLayerFrame(uint64_t contextId, WebCore::FloatRect frame)
517 {
518     @autoreleasepool {
519 #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 90000
520         BKSAnimationFenceHandle* synchronizationFence = [UIWindow _synchronizedDrawingFence];
521         mach_port_name_t fencePort = [synchronizationFence CAPort];
522 #else
523         mach_port_name_t fencePort = [UIWindow _synchronizeDrawingAcrossProcesses];
524 #endif
525
526         m_page->send(Messages::WebVideoFullscreenManager::SetVideoLayerFrameFenced(contextId, frame, IPC::Attachment(fencePort, MACH_MSG_TYPE_MOVE_SEND)), m_page->pageID());
527     }
528 }
529
530 void WebVideoFullscreenManagerProxy::setVideoLayerGravity(uint64_t contextId, WebCore::WebVideoFullscreenModel::VideoGravity gravity)
531 {
532     m_page->send(Messages::WebVideoFullscreenManager::SetVideoLayerGravityEnum(contextId, (unsigned)gravity), m_page->pageID());
533 }
534
535 void WebVideoFullscreenManagerProxy::selectAudioMediaOption(uint64_t contextId, uint64_t index)
536 {
537     m_page->send(Messages::WebVideoFullscreenManager::SelectAudioMediaOption(contextId, index), m_page->pageID());
538 }
539
540 void WebVideoFullscreenManagerProxy::selectLegibleMediaOption(uint64_t contextId, uint64_t index)
541 {
542     m_page->send(Messages::WebVideoFullscreenManager::SelectLegibleMediaOption(contextId, index), m_page->pageID());
543 }
544
545 void WebVideoFullscreenManagerProxy::fullscreenModeChanged(uint64_t contextId, WebCore::HTMLMediaElementEnums::VideoFullscreenMode mode)
546 {
547     m_page->send(Messages::WebVideoFullscreenManager::FullscreenModeChanged(contextId, mode), m_page->pageID());
548 }
549
550 void WebVideoFullscreenManagerProxy::fullscreenMayReturnToInline(uint64_t contextId)
551 {
552     bool isViewVisible = m_page->isViewVisible();
553     m_page->send(Messages::WebVideoFullscreenManager::FullscreenMayReturnToInline(contextId, isViewVisible), m_page->pageID());
554 }
555
556 #endif
557
558 } // namespace WebKit
559
560 #endif // PLATFORM(IOS)