diff --git a/LayoutTests/fast/scrolling/ios/video-scrolling-expected.txt b/LayoutTests/fast/scrolling/ios/video-scrolling-expected.txt new file mode 100644 index 000000000000..340aa84fd611 --- /dev/null +++ b/LayoutTests/fast/scrolling/ios/video-scrolling-expected.txt @@ -0,0 +1,9 @@ + +RUN(video.src = findMediaFile("video", "../../../media/content/test")) +EVENT(canplay) +RUN(video.play()) +Promise resolved OK +Simulate drag on video element +EVENT(scroll) +END OF TEST + diff --git a/LayoutTests/fast/scrolling/ios/video-scrolling.html b/LayoutTests/fast/scrolling/ios/video-scrolling.html new file mode 100644 index 000000000000..19408bbf76fd --- /dev/null +++ b/LayoutTests/fast/scrolling/ios/video-scrolling.html @@ -0,0 +1,37 @@ + + + + + + video-scrolling + + + + + + + + +
+ + \ No newline at end of file diff --git a/Source/WebKit/SourcesCocoa.txt b/Source/WebKit/SourcesCocoa.txt index 02c2f2456cdc..efed81239c80 100644 --- a/Source/WebKit/SourcesCocoa.txt +++ b/Source/WebKit/SourcesCocoa.txt @@ -500,6 +500,7 @@ UIProcess/ios/WKSyntheticTapGestureRecognizer.mm UIProcess/ios/WKTouchActionGestureRecognizer.mm UIProcess/ios/WKTextSelectionRect.mm UIProcess/ios/WKUSDPreviewView.mm +UIProcess/ios/WKVideoView.mm UIProcess/ios/WKWebEvent.mm UIProcess/ios/WKWebGeolocationPolicyDeciderIOS.mm diff --git a/Source/WebKit/UIProcess/Cocoa/VideoFullscreenManagerProxy.h b/Source/WebKit/UIProcess/Cocoa/VideoFullscreenManagerProxy.h index c056c4dd5644..95b393213191 100644 --- a/Source/WebKit/UIProcess/Cocoa/VideoFullscreenManagerProxy.h +++ b/Source/WebKit/UIProcess/Cocoa/VideoFullscreenManagerProxy.h @@ -45,6 +45,7 @@ #include OBJC_CLASS WKLayerHostView; +OBJC_CLASS WKVideoView; OBJC_CLASS WebAVPlayerLayer; OBJC_CLASS WebAVPlayerLayerView; @@ -78,6 +79,9 @@ class VideoFullscreenModelContext final #if PLATFORM(IOS_FAMILY) WebAVPlayerLayerView *playerView() const { return m_playerView.get(); } void setPlayerView(RetainPtr&& playerView) { m_playerView = WTFMove(playerView); } + + WKVideoView *videoView() const { return m_videoView.get(); } + void setVideoView(RetainPtr&& videoView) { m_videoView = WTFMove(videoView); } #endif void requestCloseAllMediaPresentations(bool finishedWithMedia, CompletionHandler&&); @@ -137,6 +141,7 @@ class VideoFullscreenModelContext final #if PLATFORM(IOS_FAMILY) RetainPtr m_playerView; + RetainPtr m_videoView; #endif HashSet m_clients; @@ -177,7 +182,7 @@ class VideoFullscreenManagerProxy : public RefCounted createViewWithID(PlaybackSessionContextIdentifier, WebKit::LayerHostingContextID videoLayerID, const WebCore::FloatSize& initialSize, const WebCore::FloatSize& nativeSize, float hostingScaleFactor); + RetainPtr createViewWithID(PlaybackSessionContextIdentifier, WebKit::LayerHostingContextID videoLayerID, const WebCore::FloatSize& initialSize, const WebCore::FloatSize& nativeSize, float hostingScaleFactor); #endif PlatformLayerContainer createLayerWithID(PlaybackSessionContextIdentifier, WebKit::LayerHostingContextID videoLayerID, const WebCore::FloatSize& initialSize, const WebCore::FloatSize& nativeSize, float hostingScaleFactor); diff --git a/Source/WebKit/UIProcess/Cocoa/VideoFullscreenManagerProxy.mm b/Source/WebKit/UIProcess/Cocoa/VideoFullscreenManagerProxy.mm index 2a242f972abf..4910ebaa6b93 100644 --- a/Source/WebKit/UIProcess/Cocoa/VideoFullscreenManagerProxy.mm +++ b/Source/WebKit/UIProcess/Cocoa/VideoFullscreenManagerProxy.mm @@ -35,6 +35,7 @@ #import "PlaybackSessionManagerProxy.h" #import "VideoFullscreenManagerMessages.h" #import "VideoFullscreenManagerProxyMessages.h" +#import "WKVideoView.h" #import "WebPageProxy.h" #import "WebProcessProxy.h" #import @@ -707,22 +708,22 @@ - (BOOL)prefersStatusBarHidden } #if PLATFORM(IOS_FAMILY) -RetainPtr VideoFullscreenManagerProxy::createViewWithID(PlaybackSessionContextIdentifier contextId, WebKit::LayerHostingContextID videoLayerID, const WebCore::FloatSize& initialSize, const WebCore::FloatSize& nativeSize, float hostingDeviceScaleFactor) +RetainPtr VideoFullscreenManagerProxy::createViewWithID(PlaybackSessionContextIdentifier contextId, WebKit::LayerHostingContextID videoLayerID, const WebCore::FloatSize& initialSize, const WebCore::FloatSize& nativeSize, float hostingDeviceScaleFactor) { auto& [model, interface] = ensureModelAndInterface(contextId); addClientForContext(contextId); RetainPtr view = createLayerHostViewWithID(contextId, videoLayerID, initialSize, hostingDeviceScaleFactor); - if (!model->playerView()) { + if (!model->videoView()) { ALWAYS_LOG(LOGIDENTIFIER, model->logIdentifier(), ", Creating AVPlayerLayerView"); - auto playerView = adoptNS([allocWebAVPlayerLayerViewInstance() init]); + auto initialFrame = CGRectMake(0, 0, initialSize.width(), initialSize.height()); + auto playerView = adoptNS([allocWebAVPlayerLayerViewInstance() initWithFrame:initialFrame]); RetainPtr playerLayer { (WebAVPlayerLayer *)[playerView layer] }; [playerLayer setVideoDimensions:nativeSize]; [playerLayer setFullscreenModel:model.get()]; - [playerLayer setVideoSublayer:[view layer]]; // The videoView may already be reparented in fullscreen, so only parent the view @@ -730,15 +731,15 @@ - (BOOL)prefersStatusBarHidden if (![[view layer] superlayer]) [playerLayer addSublayer:[view layer]]; + auto videoView = adoptNS([[WKVideoView alloc] initWithFrame:initialFrame]); + [videoView addSubview:playerView.get()]; + model->setPlayerLayer(WTFMove(playerLayer)); model->setPlayerView(playerView.get()); - - [playerView setFrame:CGRectMake(0, 0, initialSize.width(), initialSize.height())]; - [playerView setNeedsLayout]; - [playerView layoutIfNeeded]; + model->setVideoView(videoView.get()); } - return model->playerView(); + return model->videoView(); } #endif diff --git a/Source/WebKit/UIProcess/RemoteLayerTree/ios/RemoteLayerTreeHostIOS.mm b/Source/WebKit/UIProcess/RemoteLayerTree/ios/RemoteLayerTreeHostIOS.mm index 46cbe2828073..0f6c52213818 100644 --- a/Source/WebKit/UIProcess/RemoteLayerTree/ios/RemoteLayerTreeHostIOS.mm +++ b/Source/WebKit/UIProcess/RemoteLayerTree/ios/RemoteLayerTreeHostIOS.mm @@ -32,9 +32,9 @@ #import "RemoteLayerTreeViews.h" #import "UIKitSPI.h" #import "VideoFullscreenManagerProxy.h" +#import "WKVideoView.h" #import "WebPageProxy.h" #import -#import #import #if ENABLE(ARKIT_INLINE_PREVIEW_IOS) diff --git a/Source/WebKit/UIProcess/ios/WKVideoView.h b/Source/WebKit/UIProcess/ios/WKVideoView.h new file mode 100644 index 000000000000..a97ae7bca8d8 --- /dev/null +++ b/Source/WebKit/UIProcess/ios/WKVideoView.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2023 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if PLATFORM(IOS_FAMILY) + +#import "RemoteLayerTreeViews.h" + +@interface WKVideoView : WKCompositingView +@end + +#endif diff --git a/Source/WebKit/UIProcess/ios/WKVideoView.mm b/Source/WebKit/UIProcess/ios/WKVideoView.mm new file mode 100644 index 000000000000..1200025cd404 --- /dev/null +++ b/Source/WebKit/UIProcess/ios/WKVideoView.mm @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2023 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "WKVideoView.h" + +#if PLATFORM(IOS_FAMILY) +@implementation WKVideoView ++ (Class)layerClass +{ + return [CALayer class]; +} + +- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event +{ + return [self pointInside:point withEvent:event] ? self : nil; +} + +- (void)layoutSubviews +{ + for (UIView *subview in self.subviews) + subview.frame = self.bounds; +} +@end +#endif diff --git a/Source/WebKit/WebKit.xcodeproj/project.pbxproj b/Source/WebKit/WebKit.xcodeproj/project.pbxproj index 67c529abdce9..e7f404dda9ba 100644 --- a/Source/WebKit/WebKit.xcodeproj/project.pbxproj +++ b/Source/WebKit/WebKit.xcodeproj/project.pbxproj @@ -6920,6 +6920,8 @@ CDAC20F423FC383A0021DEE3 /* RemoteCDMProxyMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RemoteCDMProxyMessages.h; sourceTree = ""; }; CDAC20F523FC383B0021DEE3 /* RemoteCDMInstanceProxyMessageReceiver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RemoteCDMInstanceProxyMessageReceiver.cpp; sourceTree = ""; }; CDB2A1ED2697925C006B235C /* GPUProcessProxyCocoa.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = GPUProcessProxyCocoa.mm; sourceTree = ""; }; + CDB96AD32AB379C9007A90D3 /* WKVideoView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = WKVideoView.h; path = ios/WKVideoView.h; sourceTree = ""; }; + CDB96AD42AB379CA007A90D3 /* WKVideoView.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = WKVideoView.mm; path = ios/WKVideoView.mm; sourceTree = ""; }; CDBB49F4240D8AC60017C292 /* RemoteAudioSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RemoteAudioSession.h; sourceTree = ""; }; CDBB49F5240D8AC60017C292 /* RemoteAudioSession.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = RemoteAudioSession.cpp; sourceTree = ""; }; CDBB49F6240D8C950017C292 /* RemoteAudioSessionProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RemoteAudioSessionProxy.h; sourceTree = ""; }; @@ -9686,6 +9688,8 @@ 71A676A522C62318007D6295 /* WKTouchActionGestureRecognizer.mm */, 316B8B622054B55800BD4A62 /* WKUSDPreviewView.h */, 316B8B612054B55800BD4A62 /* WKUSDPreviewView.mm */, + CDB96AD32AB379C9007A90D3 /* WKVideoView.h */, + CDB96AD42AB379CA007A90D3 /* WKVideoView.mm */, 2D1E8221216FFF5000A15265 /* WKWebEvent.h */, 2D1E8222216FFF5100A15265 /* WKWebEvent.mm */, 463010012984778C00715DB1 /* WKWebGeolocationPolicyDecider.h */,