blob: e73d74f4c2b72fb62a9983e3139fd1e48dba9a0c [file] [log] [blame] [edit]
/*
* Copyright (C) 2024 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.
*/
#import "config.h"
#if PLATFORM(IOS_FAMILY)
#import "InstanceMethodSwizzler.h"
#import "PlatformUtilities.h"
#import "Test.h"
#import "TestWKWebView.h"
#import "WKWebViewConfigurationExtras.h"
#import <WebKit/WKWebViewPrivate.h>
#import <WebKit/_WKFullscreenDelegate.h>
#import <wtf/BlockPtr.h>
#import <wtf/RunLoop.h>
static void swizzledPresentViewController(UIViewController *, SEL, UIViewController *, BOOL, dispatch_block_t completion)
{
RunLoop::mainSingleton().dispatch([completion = makeBlockPtr(completion)] {
if (completion)
completion();
});
}
@interface FullscreenLayoutParametersWebView : TestWKWebView
@end
@implementation FullscreenLayoutParametersWebView {
std::unique_ptr<InstanceMethodSwizzler> _viewControllerPresentationSwizzler;
bool _doneEnteringFullscreen;
bool _doneExitingFullscreen;
}
- (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration
{
if (!(self = [super initWithFrame:frame configuration:configuration]))
return nil;
// Since TestWebKitAPIApp is not a real UIApplication, -presentViewController:animated:completion:
// never calls the completion handler and we never transition into WKFullscreenStateInFullscreen.
// Work around that fact by swizzling the method.
_viewControllerPresentationSwizzler = WTF::makeUnique<InstanceMethodSwizzler>(
UIViewController.class,
@selector(presentViewController:animated:completion:),
reinterpret_cast<IMP>(swizzledPresentViewController)
);
return self;
}
- (void)enterFullscreen
{
_doneEnteringFullscreen = false;
[self evaluateJavaScript:@"enterFullscreen()" completionHandler:nil];
TestWebKitAPI::Util::run(&_doneEnteringFullscreen);
[self waitForNextPresentationUpdate];
}
- (void)exitFullscreen
{
_doneExitingFullscreen = false;
[self evaluateJavaScript:@"exitFullscreen()" completionHandler:nil];
TestWebKitAPI::Util::run(&_doneExitingFullscreen);
[self waitForNextPresentationUpdate];
}
- (void)didChangeValueForKey:(NSString *)key
{
[super didChangeValueForKey:key];
if (![key isEqualToString:@"fullscreenState"])
return;
auto state = self.fullscreenState;
switch (state) {
case WKFullscreenStateNotInFullscreen:
_doneExitingFullscreen = true;
break;
case WKFullscreenStateInFullscreen:
_doneEnteringFullscreen = true;
break;
default:
break;
}
}
@end
namespace TestWebKitAPI {
TEST(Fullscreen, OverriddenLayoutParameters)
{
auto configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
configuration.preferences.elementFullscreenEnabled = YES;
auto webView = adoptNS([[FullscreenLayoutParametersWebView alloc] initWithFrame:CGRectMake(0, 0, 390, 800) configuration:configuration]);
[webView synchronouslyLoadTestPageNamed:@"element-fullscreen"];
auto layoutSize = CGSizeMake(390, 745);
[webView _overrideLayoutParametersWithMinimumLayoutSize:layoutSize minimumUnobscuredSizeOverride:layoutSize maximumUnobscuredSizeOverride:layoutSize];
[webView enterFullscreen];
[webView exitFullscreen];
EXPECT_TRUE(CGSizeEqualToSize([webView _minimumUnobscuredSizeOverride], layoutSize));
EXPECT_TRUE(CGSizeEqualToSize([webView _maximumUnobscuredSizeOverride], layoutSize));
}
TEST(Fullscreen, ResizeEventOrder)
{
auto configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES];
configuration.preferences.elementFullscreenEnabled = YES;
auto webView = adoptNS([[FullscreenLayoutParametersWebView alloc] initWithFrame:CGRectMake(0, 0, 390, 800) configuration:configuration]);
[webView synchronouslyLoadTestPageNamed:@"element-fullscreen"];
[webView waitForNextPresentationUpdate];
bool hasFullscreenChanged = false;
bool hasResized = false;
[webView objectByEvaluatingJavaScript:@(R"script(
hasFullscreenChanged = false;
document.addEventListener('fullscreenchange', () => {
hasFullscreenChanged = true;
webkit.messageHandlers.testHandler.postMessage('fullscreen-changed');
});
window.addEventListener('resize', () => {
if (!hasFullscreenChanged)
webkit.messageHandlers.testHandler.postMessage('fail');
webkit.messageHandlers.testHandler.postMessage('resize');
});)script")];
[webView performAfterReceivingMessage:@"fullscreen-changed" action:[&] { hasFullscreenChanged = true; }];
[webView performAfterReceivingMessage:@"resize" action:[&] { hasResized = true; }];
[webView performAfterReceivingMessage:@"fail" action:[] { FAIL(); }];
[webView enterFullscreen];
Util::run(&hasFullscreenChanged);
Util::run(&hasResized);
}
} // namespace TestWebKitAPI
#endif // PLATFORM(IOS_FAMILY)