blob: 57a1f4e9c75de5dfdfe0e2e4909c63265f025202 [file] [log] [blame]
/*
* Copyright (C) 2016 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"
#import "TestWKWebViewMac.h"
#if WK_API_ENABLED && PLATFORM(MAC)
#import "Utilities.h"
#import <AppKit/AppKit.h>
#import <Carbon/Carbon.h>
#import <WebKit/WebKitPrivate.h>
#import <objc/runtime.h>
#import <wtf/RetainPtr.h>
@implementation TestMessageHandler {
dispatch_block_t _handler;
NSString *_message;
}
- (instancetype)initWithMessage:(NSString *)message handler:(dispatch_block_t)handler
{
if (!(self = [super init]))
return nil;
_handler = [handler copy];
_message = message;
return self;
}
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
if ([(NSString *)[message body] isEqualToString:_message] && _handler)
_handler();
}
@end
@interface TestWKWebViewHostWindow : NSWindow
@end
@implementation TestWKWebViewHostWindow
static int gEventNumber = 1;
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101003
NSEventMask __simulated_forceClickAssociatedEventsMask(id self, SEL _cmd)
{
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200
return NSEventMaskPressure | NSEventMaskLeftMouseDown | NSEventMaskLeftMouseUp | NSEventMaskLeftMouseDragged;
#else
return NSEventMaskPressure | (1 << NSLeftMouseDown) | (1 << NSLeftMouseUp) | (1 << NSLeftMouseDragged);
#endif
}
#endif
- (void)_mouseDownAtPoint:(NSPoint)point simulatePressure:(BOOL)simulatePressure
{
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200
NSEventType mouseEventType = NSEventTypeLeftMouseDown;
#else
NSEventType mouseEventType = NSLeftMouseDown;
#endif
NSEventMask modifierFlags = 0;
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101003
if (simulatePressure)
modifierFlags |= NSEventMaskPressure;
#else
simulatePressure = NO;
#endif
NSEvent *event = [NSEvent mouseEventWithType:mouseEventType location:point modifierFlags:modifierFlags timestamp:GetCurrentEventTime() windowNumber:self.windowNumber context:[NSGraphicsContext currentContext] eventNumber:++gEventNumber clickCount:1 pressure:simulatePressure];
if (!simulatePressure) {
[self sendEvent:event];
return;
}
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101003
IMP simulatedAssociatedEventsMaskImpl = (IMP)__simulated_forceClickAssociatedEventsMask;
Method associatedEventsMaskMethod = class_getInstanceMethod([NSEvent class], @selector(associatedEventsMask));
IMP originalAssociatedEventsMaskImpl = method_setImplementation(associatedEventsMaskMethod, simulatedAssociatedEventsMaskImpl);
@try {
[self sendEvent:event];
} @finally {
// In the case where event sending raises an exception, we still want to restore the original implementation
// to prevent subsequent event sending tests from being affected.
method_setImplementation(associatedEventsMaskMethod, originalAssociatedEventsMaskImpl);
}
#endif
}
@end
@implementation TestWKWebView {
TestWKWebViewHostWindow *_hostWindow;
}
- (instancetype)initWithFrame:(CGRect)frame
{
WKWebViewConfiguration *defaultConfiguration = [[WKWebViewConfiguration alloc] init];
return [self initWithFrame:frame configuration:defaultConfiguration];
}
- (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration
{
if (self = [super initWithFrame:frame configuration:configuration])
[self _setUpTestWindow:frame];
return self;
}
- (void)_setUpTestWindow:(NSRect)frame
{
_hostWindow = [[TestWKWebViewHostWindow alloc] initWithContentRect:frame styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
[_hostWindow setFrameOrigin:NSMakePoint(0, 0)];
[[_hostWindow contentView] addSubview:self];
[_hostWindow setIsVisible:YES];
[_hostWindow makeKeyAndOrderFront:self];
}
- (void)mouseDownAtPoint:(NSPoint)point simulatePressure:(BOOL)simulatePressure
{
[_hostWindow _mouseDownAtPoint:point simulatePressure:simulatePressure];
}
- (void)performAfterReceivingMessage:(NSString *)message action:(dispatch_block_t)action
{
RetainPtr<TestMessageHandler> handler = adoptNS([[TestMessageHandler alloc] initWithMessage:message handler:action]);
WKUserContentController* contentController = [[self configuration] userContentController];
[contentController removeScriptMessageHandlerForName:@"testHandler"];
[contentController addScriptMessageHandler:handler.get() name:@"testHandler"];
}
- (void)loadTestPageNamed:(NSString *)pageName
{
NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:pageName withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
[self loadRequest:request];
}
- (void)typeCharacter:(char)character {
NSString *characterAsString = [NSString stringWithFormat:@"%c" , character];
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200
NSEventType keyDownEventType = NSEventTypeKeyDown;
NSEventType keyUpEventType = NSEventTypeKeyUp;
#else
NSEventType keyDownEventType = NSKeyDown;
NSEventType keyUpEventType = NSKeyUp;
#endif
[self keyDown:[NSEvent keyEventWithType:keyDownEventType location:NSZeroPoint modifierFlags:0 timestamp:GetCurrentEventTime() windowNumber:_hostWindow.windowNumber context:nil characters:characterAsString charactersIgnoringModifiers:characterAsString isARepeat:NO keyCode:character]];
[self keyUp:[NSEvent keyEventWithType:keyUpEventType location:NSZeroPoint modifierFlags:0 timestamp:GetCurrentEventTime() windowNumber:_hostWindow.windowNumber context:nil characters:characterAsString charactersIgnoringModifiers:characterAsString isARepeat:NO keyCode:character]];
}
- (NSString *)stringByEvaluatingJavaScript:(NSString *)script
{
__block bool isWaitingForJavaScript = false;
__block NSString *evalResult = nil;
[self evaluateJavaScript:script completionHandler:^(id result, NSError *error)
{
evalResult = [NSString stringWithFormat:@"%@", result];
isWaitingForJavaScript = true;
EXPECT_TRUE(!error);
}];
TestWebKitAPI::Util::run(&isWaitingForJavaScript);
return evalResult;
}
- (void)waitForMessage:(NSString *)message
{
__block bool isDoneWaiting = false;
[self performAfterReceivingMessage:message action:^()
{
isDoneWaiting = true;
}];
TestWebKitAPI::Util::run(&isDoneWaiting);
}
- (void)performAfterLoading:(dispatch_block_t)actions {
TestMessageHandler *handler = [[TestMessageHandler alloc] initWithMessage:@"loaded" handler:actions];
NSString *onloadScript = @"window.onload = () => window.webkit.messageHandlers.onloadHandler.postMessage('loaded')";
WKUserScript *script = [[WKUserScript alloc] initWithSource:onloadScript injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
WKUserContentController* contentController = [[self configuration] userContentController];
[contentController addUserScript:script];
[contentController addScriptMessageHandler:handler name:@"onloadHandler"];
}
@end
#endif /* WK_API_ENABLED && PLATFORM(MAC) */