2 * Copyright (C) 2010, 2013, 2015 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #import "PlatformWebView.h"
29 #import "TestController.h"
30 #import "WebKitTestRunnerDraggingInfo.h"
31 #import <WebKit/WKImageCG.h>
32 #import <WebKit/WKPreferencesPrivate.h>
33 #import <WebKit/WKWebViewConfiguration.h>
34 #import <WebKit/WKWebViewPrivate.h>
35 #import <wtf/RetainPtr.h>
38 @interface WKWebView (Details)
39 - (WKPageRef)_pageForTesting;
46 _NSBackingStoreUnbuffered = 3
49 @interface WebKitTestRunnerWindow : NSWindow {
50 PlatformWebView* _platformWebView;
53 @property (nonatomic, assign) PlatformWebView* platformWebView;
57 @interface TestRunnerWKWebView : WKWebView
60 @implementation TestRunnerWKWebView
62 - (void)dragImage:(NSImage *)anImage at:(NSPoint)viewLocation offset:(NSSize)initialOffset event:(NSEvent *)event pasteboard:(NSPasteboard *)pboard source:(id)sourceObj slideBack:(BOOL)slideFlag
64 RetainPtr<WebKitTestRunnerDraggingInfo> draggingInfo = adoptNS([[WebKitTestRunnerDraggingInfo alloc] initWithImage:anImage offset:initialOffset pasteboard:pboard source:sourceObj]);
65 [self draggingUpdated:draggingInfo.get()];
71 @implementation WebKitTestRunnerWindow
72 @synthesize platformWebView = _platformWebView;
76 return _platformWebView ? _platformWebView->windowIsKey() : YES;
79 - (void)setFrameOrigin:(NSPoint)point
84 - (void)setFrame:(NSRect)windowFrame display:(BOOL)displayViews animate:(BOOL)performAnimation
86 NSRect currentFrame = [super frame];
88 _fakeOrigin = windowFrame.origin;
90 [super setFrame:NSMakeRect(currentFrame.origin.x, currentFrame.origin.y, windowFrame.size.width, windowFrame.size.height) display:displayViews animate:performAnimation];
93 - (void)setFrame:(NSRect)windowFrame display:(BOOL)displayViews
95 NSRect currentFrame = [super frame];
97 _fakeOrigin = windowFrame.origin;
99 [super setFrame:NSMakeRect(currentFrame.origin.x, currentFrame.origin.y, windowFrame.size.width, windowFrame.size.height) display:displayViews];
102 - (NSRect)frameRespectingFakeOrigin
104 NSRect currentFrame = [self frame];
105 return NSMakeRect(_fakeOrigin.x, _fakeOrigin.y, currentFrame.size.width, currentFrame.size.height);
109 @interface NSWindow ()
111 - (void)_setWindowResolution:(CGFloat)resolution displayIfChanged:(BOOL)displayIfChanged;
117 PlatformWebView::PlatformWebView(WKWebViewConfiguration* configuration, const TestOptions& options)
118 : m_windowIsKey(true)
122 // FIXME: Not sure this is the best place for this; maybe we should have API to set this so we can do it from TestController?
123 if (m_options.useRemoteLayerTree)
124 [[NSUserDefaults standardUserDefaults] setValue:@YES forKey:@"WebKit2UseRemoteLayerTreeDrawingArea"];
126 RetainPtr<WKWebViewConfiguration> copiedConfiguration = adoptNS([configuration copy]);
127 WKPreferencesSetThreadedScrollingEnabled((WKPreferencesRef)[copiedConfiguration preferences], m_options.useThreadedScrolling);
129 NSRect rect = NSMakeRect(0, 0, TestController::viewWidth, TestController::viewHeight);
130 m_view = [[TestRunnerWKWebView alloc] initWithFrame:rect configuration:copiedConfiguration.get()];
131 [m_view _setWindowOcclusionDetectionEnabled:NO];
133 NSScreen *firstScreen = [[NSScreen screens] objectAtIndex:0];
134 NSRect windowRect = m_options.shouldShowWebView ? NSOffsetRect(rect, 100, 100) : NSOffsetRect(rect, -10000, [firstScreen frame].size.height - rect.size.height + 10000);
135 m_window = [[WebKitTestRunnerWindow alloc] initWithContentRect:windowRect styleMask:NSBorderlessWindowMask backing:(NSBackingStoreType)_NSBackingStoreUnbuffered defer:YES];
136 m_window.platformWebView = this;
137 [m_window setColorSpace:[firstScreen colorSpace]];
138 [m_window setCollectionBehavior:NSWindowCollectionBehaviorStationary];
139 [[m_window contentView] addSubview:m_view];
140 if (m_options.shouldShowWebView)
141 [m_window orderFront:nil];
143 [m_window orderBack:nil];
144 [m_window setReleasedWhenClosed:NO];
148 void PlatformWebView::resizeTo(unsigned width, unsigned height)
150 WKRect frame = windowFrame();
151 frame.size.width = width;
152 frame.size.height = height;
153 setWindowFrame(frame);
156 PlatformWebView::~PlatformWebView()
158 m_window.platformWebView = nullptr;
164 WKPageRef PlatformWebView::page()
167 return [m_view _pageForTesting];
173 void PlatformWebView::focus()
175 [m_window makeFirstResponder:platformView()];
176 setWindowIsKey(true);
179 WKRect PlatformWebView::windowFrame()
181 NSRect frame = [m_window frameRespectingFakeOrigin];
184 wkFrame.origin.x = frame.origin.x;
185 wkFrame.origin.y = frame.origin.y;
186 wkFrame.size.width = frame.size.width;
187 wkFrame.size.height = frame.size.height;
191 void PlatformWebView::setWindowFrame(WKRect frame)
193 [m_window setFrame:NSMakeRect(frame.origin.x, frame.origin.y, frame.size.width, frame.size.height) display:YES];
194 [platformView() setFrame:NSMakeRect(0, 0, frame.size.width, frame.size.height)];
197 void PlatformWebView::didInitializeClients()
199 // Set a temporary 1x1 window frame to force a WindowAndViewFramesChanged notification. <rdar://problem/13380145>
200 forceWindowFramesChanged();
203 void PlatformWebView::addChromeInputField()
205 NSTextField *textField = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 20)];
207 [[m_window contentView] addSubview:textField];
210 NSView *view = platformView();
211 [textField setNextKeyView:view];
212 [view setNextKeyView:textField];
215 void PlatformWebView::removeChromeInputField()
217 NSView *textField = [[m_window contentView] viewWithTag:1];
219 [textField removeFromSuperview];
220 makeWebViewFirstResponder();
224 void PlatformWebView::makeWebViewFirstResponder()
226 [m_window makeFirstResponder:platformView()];
229 WKRetainPtr<WKImageRef> PlatformWebView::windowSnapshotImage()
231 [platformView() display];
232 CGWindowImageOption options = kCGWindowImageBoundsIgnoreFraming | kCGWindowImageShouldBeOpaque;
234 if ([m_window backingScaleFactor] == 1)
235 options |= kCGWindowImageNominalResolution;
237 RetainPtr<CGImageRef> windowSnapshotImage = adoptCF(CGWindowListCreateImage(CGRectNull, kCGWindowListOptionIncludingWindow, [m_window windowNumber], options));
239 // windowSnapshotImage will be in GenericRGB, as we've set the main display's color space to GenericRGB.
240 return adoptWK(WKImageCreateFromCGImage(windowSnapshotImage.get(), 0));
243 bool PlatformWebView::viewSupportsOptions(const TestOptions& options) const
245 if (m_options.useThreadedScrolling != options.useThreadedScrolling)
251 void PlatformWebView::changeWindowScaleIfNeeded(float newScale)
253 CGFloat currentScale = [m_window backingScaleFactor];
254 if (currentScale == newScale)
256 [m_window _setWindowResolution:newScale displayIfChanged:YES];
257 // Instead of re-constructing the current window, let's fake resize it to ensure that the scale change gets picked up.
258 forceWindowFramesChanged();
259 // Changing the scaling factor on the window does not trigger NSWindowDidChangeBackingPropertiesNotification. We need to send the notification manually.
260 RetainPtr<NSMutableDictionary> notificationUserInfo = adoptNS([[NSMutableDictionary alloc] initWithCapacity:1]);
261 [notificationUserInfo setObject:[NSNumber numberWithDouble:currentScale] forKey:NSBackingPropertyOldScaleFactorKey];
262 [[NSNotificationCenter defaultCenter] postNotificationName:NSWindowDidChangeBackingPropertiesNotification object:m_window userInfo:notificationUserInfo.get()];
265 void PlatformWebView::forceWindowFramesChanged()
267 WKRect wkFrame = windowFrame();
268 [m_window setFrame:NSMakeRect(0, 0, 1, 1) display:YES];
269 setWindowFrame(wkFrame);
272 void PlatformWebView::setNavigationGesturesEnabled(bool enabled)
275 [platformView() setAllowsBackForwardNavigationGestures:enabled];