Skip to content

Commit

Permalink
Cherry-pick 960e0d1. rdar://114720841
Browse files Browse the repository at this point in the history
    [iOS] Cannot scroll page by dragging on a bare <video> element
    https://bugs.webkit.org/show_bug.cgi?id=261563
    rdar://114720841

    Reviewed by Simon Fraser.

    The UI-side compositing subsystem relies on UIViews of particular classes or conforming to
    particular protocols for collecting the appropriate views during hit testing. WebAVPlayerLayerView
    is not one of those clasess, nor can it conform to the protocols defined in WebKit (as it's a
    product of WebCore). So to the hit testing logic of UI-side compositing, it's a black hole.

    Add a new class, WKVideoView, which is a WKCompositingView as well as WKNativelyInteractible, to
    host the WebAVPlayerLayerView.

    * Source/WebKit/SourcesCocoa.txt:
    * Source/WebKit/UIProcess/Cocoa/VideoFullscreenManagerProxy.h:
    * Source/WebKit/UIProcess/Cocoa/VideoFullscreenManagerProxy.mm:
    (WebKit::VideoFullscreenManagerProxy::createViewWithID):
    * Source/WebKit/UIProcess/RemoteLayerTree/ios/RemoteLayerTreeHostIOS.mm:
    * Source/WebKit/UIProcess/ios/WKVideoView.h: Added.
    * Source/WebKit/UIProcess/ios/WKVideoView.mm: Added.
    (+[WKVideoView layerClass]):
    (-[WKVideoView hitTest:withEvent:]):
    * Source/WebKit/WebKit.xcodeproj/project.pbxproj:

    Canonical link: https://commits.webkit.org/268041@main
Identifier: 265870.602@safari-7616.2.9.10-branch
  • Loading branch information
jernoble authored and MyahCobbs committed Sep 28, 2023
1 parent 770aa95 commit b50bdd1
Show file tree
Hide file tree
Showing 9 changed files with 150 additions and 11 deletions.
9 changes: 9 additions & 0 deletions LayoutTests/fast/scrolling/ios/video-scrolling-expected.txt
Original file line number Diff line number Diff line change
@@ -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

37 changes: 37 additions & 0 deletions LayoutTests/fast/scrolling/ios/video-scrolling.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>video-scrolling</title>
<script src=../../../media/video-test.js></script>
<script src=../../../media/media-file.js></script>
<script src=../../../resources/basic-gestures.js></script>
<script>
async function runTest() {
findMediaElement();
run('video.src = findMediaFile("video", "../../../media/content/test")');
await waitFor(video, 'canplay');
await shouldResolve(run('video.play()'));

consoleWrite('Simulate drag on video element');

let middleX = video.offsetLeft + video.offsetWidth / 2;
let middleY = video.offsetTop + video.offsetHeight / 2;
touchAndDragFromPointToPoint(middleX, middleY, middleX, 0);
await waitFor(document, 'scroll');
}

window.addEventListener('load', event => {
runTest().then(endTest).catch(failTest);
})
</script>
<style>
#spacer { width: 100vw; height: 100vh; }
</style>
</head>
<body>
<video muted playsinline></video>
<div id=spacer></div>
</body>
</html>
1 change: 1 addition & 0 deletions Source/WebKit/SourcesCocoa.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
7 changes: 6 additions & 1 deletion Source/WebKit/UIProcess/Cocoa/VideoFullscreenManagerProxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include <wtf/text/WTFString.h>

OBJC_CLASS WKLayerHostView;
OBJC_CLASS WKVideoView;
OBJC_CLASS WebAVPlayerLayer;
OBJC_CLASS WebAVPlayerLayerView;

Expand Down Expand Up @@ -78,6 +79,9 @@ class VideoFullscreenModelContext final
#if PLATFORM(IOS_FAMILY)
WebAVPlayerLayerView *playerView() const { return m_playerView.get(); }
void setPlayerView(RetainPtr<WebAVPlayerLayerView>&& playerView) { m_playerView = WTFMove(playerView); }

WKVideoView *videoView() const { return m_videoView.get(); }
void setVideoView(RetainPtr<WKVideoView>&& videoView) { m_videoView = WTFMove(videoView); }
#endif

void requestCloseAllMediaPresentations(bool finishedWithMedia, CompletionHandler<void()>&&);
Expand Down Expand Up @@ -137,6 +141,7 @@ class VideoFullscreenModelContext final

#if PLATFORM(IOS_FAMILY)
RetainPtr<WebAVPlayerLayerView> m_playerView;
RetainPtr<WKVideoView> m_videoView;
#endif

HashSet<WebCore::VideoFullscreenModelClient*> m_clients;
Expand Down Expand Up @@ -177,7 +182,7 @@ class VideoFullscreenManagerProxy : public RefCounted<VideoFullscreenManagerProx

#if PLATFORM(IOS_FAMILY)
AVPlayerViewController *playerViewController(PlaybackSessionContextIdentifier) const;
RetainPtr<WebAVPlayerLayerView> createViewWithID(PlaybackSessionContextIdentifier, WebKit::LayerHostingContextID videoLayerID, const WebCore::FloatSize& initialSize, const WebCore::FloatSize& nativeSize, float hostingScaleFactor);
RetainPtr<WKVideoView> 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);
Expand Down
19 changes: 10 additions & 9 deletions Source/WebKit/UIProcess/Cocoa/VideoFullscreenManagerProxy.mm
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#import "PlaybackSessionManagerProxy.h"
#import "VideoFullscreenManagerMessages.h"
#import "VideoFullscreenManagerProxyMessages.h"
#import "WKVideoView.h"
#import "WebPageProxy.h"
#import "WebProcessProxy.h"
#import <QuartzCore/CoreAnimation.h>
Expand Down Expand Up @@ -707,38 +708,38 @@ - (BOOL)prefersStatusBarHidden
}

#if PLATFORM(IOS_FAMILY)
RetainPtr<WebAVPlayerLayerView> VideoFullscreenManagerProxy::createViewWithID(PlaybackSessionContextIdentifier contextId, WebKit::LayerHostingContextID videoLayerID, const WebCore::FloatSize& initialSize, const WebCore::FloatSize& nativeSize, float hostingDeviceScaleFactor)
RetainPtr<WKVideoView> 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<WKLayerHostView> 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
// if it has no existing parent:
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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@
#import "RemoteLayerTreeViews.h"
#import "UIKitSPI.h"
#import "VideoFullscreenManagerProxy.h"
#import "WKVideoView.h"
#import "WebPageProxy.h"
#import <UIKit/UIScrollView.h>
#import <WebCore/WebAVPlayerLayerView.h>
#import <pal/spi/cocoa/QuartzCoreSPI.h>

#if ENABLE(ARKIT_INLINE_PREVIEW_IOS)
Expand Down
35 changes: 35 additions & 0 deletions Source/WebKit/UIProcess/ios/WKVideoView.h
Original file line number Diff line number Diff line change
@@ -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 <WKNativelyInteractible>
@end

#endif
47 changes: 47 additions & 0 deletions Source/WebKit/UIProcess/ios/WKVideoView.mm
Original file line number Diff line number Diff line change
@@ -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
4 changes: 4 additions & 0 deletions Source/WebKit/WebKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -6920,6 +6920,8 @@
CDAC20F423FC383A0021DEE3 /* RemoteCDMProxyMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RemoteCDMProxyMessages.h; sourceTree = "<group>"; };
CDAC20F523FC383B0021DEE3 /* RemoteCDMInstanceProxyMessageReceiver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RemoteCDMInstanceProxyMessageReceiver.cpp; sourceTree = "<group>"; };
CDB2A1ED2697925C006B235C /* GPUProcessProxyCocoa.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = GPUProcessProxyCocoa.mm; sourceTree = "<group>"; };
CDB96AD32AB379C9007A90D3 /* WKVideoView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = WKVideoView.h; path = ios/WKVideoView.h; sourceTree = "<group>"; };
CDB96AD42AB379CA007A90D3 /* WKVideoView.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = WKVideoView.mm; path = ios/WKVideoView.mm; sourceTree = "<group>"; };
CDBB49F4240D8AC60017C292 /* RemoteAudioSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RemoteAudioSession.h; sourceTree = "<group>"; };
CDBB49F5240D8AC60017C292 /* RemoteAudioSession.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = RemoteAudioSession.cpp; sourceTree = "<group>"; };
CDBB49F6240D8C950017C292 /* RemoteAudioSessionProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RemoteAudioSessionProxy.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -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 */,
Expand Down

0 comments on commit b50bdd1

Please sign in to comment.