Don't use (Details) when exposing SPI
[WebKit-https.git] / Tools / WebKitTestRunner / mac / PlatformWebViewMac.mm
1 /*
2  * Copyright (C) 2010, 2013, 2015 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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.
24  */
25
26 #import "config.h"
27 #import "PlatformWebView.h"
28
29 #import "TestController.h"
30 #import "WebKitTestRunnerDraggingInfo.h"
31 #import <WebKit/WKImageCG.h>
32 #import <WebKit/WKPreferencesPrivate.h>
33 #import <WebKit/WKViewPrivate.h>
34 #import <wtf/RetainPtr.h>
35
36 using namespace WTR;
37
38 enum {
39     _NSBackingStoreUnbuffered = 3
40 };
41
42 @interface WebKitTestRunnerWindow : NSWindow {
43     PlatformWebView* _platformWebView;
44     NSPoint _fakeOrigin;
45 }
46 @property (nonatomic, assign) PlatformWebView* platformWebView;
47 @end
48
49 @interface TestRunnerWKView : WKView {
50     BOOL _useThreadedScrolling;
51 }
52
53 - (id)initWithFrame:(NSRect)frame contextRef:(WKContextRef)context pageGroupRef:(WKPageGroupRef)pageGroup relatedToPage:(WKPageRef)relatedPage useThreadedScrolling:(BOOL)useThreadedScrolling;
54
55 @property (nonatomic, assign) BOOL useThreadedScrolling;
56 @end
57
58 @implementation TestRunnerWKView
59
60 @synthesize useThreadedScrolling = _useThreadedScrolling;
61
62 - (id)initWithFrame:(NSRect)frame contextRef:(WKContextRef)context pageGroupRef:(WKPageGroupRef)pageGroup relatedToPage:(WKPageRef)relatedPage useThreadedScrolling:(BOOL)useThreadedScrolling
63 {
64     _useThreadedScrolling = useThreadedScrolling;
65     return [super initWithFrame:frame contextRef:context pageGroupRef:pageGroup relatedToPage:relatedPage];
66 }
67
68 - (void)dragImage:(NSImage *)anImage at:(NSPoint)viewLocation offset:(NSSize)initialOffset event:(NSEvent *)event pasteboard:(NSPasteboard *)pboard source:(id)sourceObj slideBack:(BOOL)slideFlag
69 {
70     RetainPtr<WebKitTestRunnerDraggingInfo> draggingInfo = adoptNS([[WebKitTestRunnerDraggingInfo alloc] initWithImage:anImage offset:initialOffset pasteboard:pboard source:sourceObj]);
71     [self draggingUpdated:draggingInfo.get()];
72 }
73
74 @end
75
76 @implementation WebKitTestRunnerWindow
77 @synthesize platformWebView = _platformWebView;
78
79 - (BOOL)isKeyWindow
80 {
81     return _platformWebView ? _platformWebView->windowIsKey() : YES;
82 }
83
84 - (void)setFrameOrigin:(NSPoint)point
85 {
86     _fakeOrigin = point;
87 }
88
89 - (void)setFrame:(NSRect)windowFrame display:(BOOL)displayViews animate:(BOOL)performAnimation
90 {
91     NSRect currentFrame = [super frame];
92
93     _fakeOrigin = windowFrame.origin;
94
95     [super setFrame:NSMakeRect(currentFrame.origin.x, currentFrame.origin.y, windowFrame.size.width, windowFrame.size.height) display:displayViews animate:performAnimation];
96 }
97
98 - (void)setFrame:(NSRect)windowFrame display:(BOOL)displayViews
99 {
100     NSRect currentFrame = [super frame];
101
102     _fakeOrigin = windowFrame.origin;
103
104     [super setFrame:NSMakeRect(currentFrame.origin.x, currentFrame.origin.y, windowFrame.size.width, windowFrame.size.height) display:displayViews];
105 }
106
107 - (NSRect)frameRespectingFakeOrigin
108 {
109     NSRect currentFrame = [self frame];
110     return NSMakeRect(_fakeOrigin.x, _fakeOrigin.y, currentFrame.size.width, currentFrame.size.height);
111 }
112 @end
113
114 @interface NSWindow ()
115
116 - (void)_setWindowResolution:(CGFloat)resolution displayIfChanged:(BOOL)displayIfChanged;
117
118 @end
119
120 namespace WTR {
121
122 PlatformWebView::PlatformWebView(WKContextRef contextRef, WKPageGroupRef pageGroupRef, WKPageRef relatedPage, WKDictionaryRef options)
123     : m_windowIsKey(true)
124     , m_options(options)
125 {
126     WKRetainPtr<WKStringRef> useThreadedScrollingKey(AdoptWK, WKStringCreateWithUTF8CString("ThreadedScrolling"));
127     WKRetainPtr<WKStringRef> useRemoteLayerTreeKey(AdoptWK, WKStringCreateWithUTF8CString("RemoteLayerTree"));
128     WKTypeRef useThreadedScrollingValue = options ? WKDictionaryGetItemForKey(options, useThreadedScrollingKey.get()) : NULL;
129     bool useThreadedScrolling = useThreadedScrollingValue && WKBooleanGetValue(static_cast<WKBooleanRef>(useThreadedScrollingValue));
130
131     // The tiled drawing specific tests also depend on threaded scrolling.
132     WKPreferencesRef preferences = WKPageGroupGetPreferences(pageGroupRef);
133     WKPreferencesSetThreadedScrollingEnabled(preferences, useThreadedScrolling);
134
135     // 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?
136     WKTypeRef useRemoteLayerTreeValue = options ? WKDictionaryGetItemForKey(options, useRemoteLayerTreeKey.get()) : NULL;
137     if (useRemoteLayerTreeValue && WKBooleanGetValue(static_cast<WKBooleanRef>(useRemoteLayerTreeValue)))
138         [[NSUserDefaults standardUserDefaults] setValue:@YES forKey:@"WebKit2UseRemoteLayerTreeDrawingArea"];
139
140     NSRect rect = NSMakeRect(0, 0, TestController::viewWidth, TestController::viewHeight);
141     m_view = [[TestRunnerWKView alloc] initWithFrame:rect contextRef:contextRef pageGroupRef:pageGroupRef relatedToPage:relatedPage useThreadedScrolling:useThreadedScrolling];
142     [m_view setWindowOcclusionDetectionEnabled:NO];
143
144     WKRetainPtr<WKStringRef> shouldShowWebViewKey(AdoptWK, WKStringCreateWithUTF8CString("ShouldShowWebView"));
145     WKTypeRef shouldShowWebViewValue = options ? WKDictionaryGetItemForKey(options, shouldShowWebViewKey.get()) : NULL;
146     bool shouldShowWebView = shouldShowWebViewValue && WKBooleanGetValue(static_cast<WKBooleanRef>(shouldShowWebViewValue));
147
148     NSScreen *firstScreen = [[NSScreen screens] objectAtIndex:0];
149     NSRect windowRect = (shouldShowWebView) ? NSOffsetRect(rect, 100, 100) : NSOffsetRect(rect, -10000, [firstScreen frame].size.height - rect.size.height + 10000);
150     m_window = [[WebKitTestRunnerWindow alloc] initWithContentRect:windowRect styleMask:NSBorderlessWindowMask backing:(NSBackingStoreType)_NSBackingStoreUnbuffered defer:YES];
151     m_window.platformWebView = this;
152     [m_window setColorSpace:[firstScreen colorSpace]];
153     [m_window setCollectionBehavior:NSWindowCollectionBehaviorStationary];
154     [[m_window contentView] addSubview:m_view];
155     if (shouldShowWebView)
156         [m_window orderFront:nil];
157     else
158         [m_window orderBack:nil];
159     [m_window setReleasedWhenClosed:NO];
160 }
161
162 void PlatformWebView::resizeTo(unsigned width, unsigned height)
163 {
164     WKRect frame = windowFrame();
165     frame.size.width = width;
166     frame.size.height = height;
167     setWindowFrame(frame);
168 }
169
170 PlatformWebView::~PlatformWebView()
171 {
172     m_window.platformWebView = nullptr;
173     [m_window close];
174     [m_window release];
175     [m_view release];
176 }
177
178 WKPageRef PlatformWebView::page()
179 {
180     return [m_view pageRef];
181 }
182
183 void PlatformWebView::focus()
184 {
185     [m_window makeFirstResponder:m_view];
186     setWindowIsKey(true);
187 }
188
189 WKRect PlatformWebView::windowFrame()
190 {
191     NSRect frame = [m_window frameRespectingFakeOrigin];
192
193     WKRect wkFrame;
194     wkFrame.origin.x = frame.origin.x;
195     wkFrame.origin.y = frame.origin.y;
196     wkFrame.size.width = frame.size.width;
197     wkFrame.size.height = frame.size.height;
198     return wkFrame;
199 }
200
201 void PlatformWebView::setWindowFrame(WKRect frame)
202 {
203     [m_window setFrame:NSMakeRect(frame.origin.x, frame.origin.y, frame.size.width, frame.size.height) display:YES];
204     [m_view setFrame:NSMakeRect(0, 0, frame.size.width, frame.size.height)];
205 }
206
207 void PlatformWebView::didInitializeClients()
208 {
209     // Set a temporary 1x1 window frame to force a WindowAndViewFramesChanged notification. <rdar://problem/13380145>
210     forceWindowFramesChanged();
211 }
212
213 void PlatformWebView::addChromeInputField()
214 {
215     NSTextField* textField = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 20)];
216     textField.tag = 1;
217     [[m_window contentView] addSubview:textField];
218     [textField release];
219
220     [textField setNextKeyView:m_view];
221     [m_view setNextKeyView:textField];
222 }
223
224 void PlatformWebView::removeChromeInputField()
225 {
226     NSView* textField = [[m_window contentView] viewWithTag:1];
227     if (textField) {
228         [textField removeFromSuperview];
229         makeWebViewFirstResponder();
230     }
231 }
232
233 void PlatformWebView::makeWebViewFirstResponder()
234 {
235     [m_window makeFirstResponder:m_view];
236 }
237
238 WKRetainPtr<WKImageRef> PlatformWebView::windowSnapshotImage()
239 {
240     [m_view display];
241     CGWindowImageOption options = kCGWindowImageBoundsIgnoreFraming | kCGWindowImageShouldBeOpaque;
242
243     if ([m_window backingScaleFactor] == 1)
244         options |= kCGWindowImageNominalResolution;
245
246     RetainPtr<CGImageRef> windowSnapshotImage = adoptCF(CGWindowListCreateImage(CGRectNull, kCGWindowListOptionIncludingWindow, [m_window windowNumber], options));
247
248     // windowSnapshotImage will be in GenericRGB, as we've set the main display's color space to GenericRGB.
249     return adoptWK(WKImageCreateFromCGImage(windowSnapshotImage.get(), 0));
250 }
251
252 bool PlatformWebView::viewSupportsOptions(WKDictionaryRef options) const
253 {
254     WKRetainPtr<WKStringRef> useThreadedScrollingKey(AdoptWK, WKStringCreateWithUTF8CString("ThreadedScrolling"));
255     WKTypeRef useThreadedScrollingValue = WKDictionaryGetItemForKey(options, useThreadedScrollingKey.get());
256     bool useThreadedScrolling = useThreadedScrollingValue && WKBooleanGetValue(static_cast<WKBooleanRef>(useThreadedScrollingValue));
257
258     return useThreadedScrolling == [(TestRunnerWKView *)m_view useThreadedScrolling];
259 }
260
261 void PlatformWebView::changeWindowScaleIfNeeded(float newScale)
262 {
263     CGFloat currentScale = [m_window backingScaleFactor];
264     if (currentScale == newScale)
265         return;
266     [m_window _setWindowResolution:newScale displayIfChanged:YES];
267     // Instead of re-constructing the current window, let's fake resize it to ensure that the scale change gets picked up.
268     forceWindowFramesChanged();
269     // Changing the scaling factor on the window does not trigger NSWindowDidChangeBackingPropertiesNotification. We need to send the notification manually.
270     RetainPtr<NSMutableDictionary> notificationUserInfo = adoptNS([[NSMutableDictionary alloc] initWithCapacity:1]);
271     [notificationUserInfo setObject:[NSNumber numberWithDouble:currentScale] forKey:NSBackingPropertyOldScaleFactorKey];
272     [[NSNotificationCenter defaultCenter] postNotificationName:NSWindowDidChangeBackingPropertiesNotification object:m_window userInfo:notificationUserInfo.get()];
273 }
274
275 void PlatformWebView::forceWindowFramesChanged()
276 {
277     WKRect wkFrame = windowFrame();
278     [m_window setFrame:NSMakeRect(0, 0, 1, 1) display:YES];
279     setWindowFrame(wkFrame);
280 }
281
282 } // namespace WTR