Fix several memory leaks found by code inspection
[WebKit-https.git] / Tools / WebKitTestRunner / mac / PlatformWebViewMac.mm
1 /*
2  * Copyright (C) 2010, 2013 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 <WebKit2/WKImageCG.h>
32 #import <WebKit2/WKPreferencesPrivate.h>
33 #import <WebKit2/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 (Details)
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     NSRect windowRect = NSOffsetRect(rect, -10000, [(NSScreen *)[[NSScreen screens] objectAtIndex:0] frame].size.height - rect.size.height + 10000);
145     m_window = [[WebKitTestRunnerWindow alloc] initWithContentRect:windowRect styleMask:NSBorderlessWindowMask backing:(NSBackingStoreType)_NSBackingStoreUnbuffered defer:YES];
146     m_window.platformWebView = this;
147     [m_window setColorSpace:[[NSScreen mainScreen] colorSpace]];
148     [m_window setCollectionBehavior:NSWindowCollectionBehaviorStationary];
149     [[m_window contentView] addSubview:m_view];
150     [m_window orderBack:nil];
151     [m_window setReleasedWhenClosed:NO];
152 }
153
154 void PlatformWebView::resizeTo(unsigned width, unsigned height)
155 {
156     NSRect windowFrame = [m_window frame];
157     windowFrame.size.width = width;
158     windowFrame.size.height = height;
159     [m_window setFrame:windowFrame display:YES];
160     [m_view setFrame:NSMakeRect(0, 0, width, height)];
161 }
162
163 PlatformWebView::~PlatformWebView()
164 {
165     m_window.platformWebView = 0;
166     [m_window close];
167     [m_window release];
168     [m_view release];
169 }
170
171 WKPageRef PlatformWebView::page()
172 {
173     return [m_view pageRef];
174 }
175
176 void PlatformWebView::focus()
177 {
178     [m_window makeFirstResponder:m_view];
179     setWindowIsKey(true);
180 }
181
182 WKRect PlatformWebView::windowFrame()
183 {
184     NSRect frame = [m_window frameRespectingFakeOrigin];
185
186     WKRect wkFrame;
187     wkFrame.origin.x = frame.origin.x;
188     wkFrame.origin.y = frame.origin.y;
189     wkFrame.size.width = frame.size.width;
190     wkFrame.size.height = frame.size.height;
191     return wkFrame;
192 }
193
194 void PlatformWebView::setWindowFrame(WKRect frame)
195 {
196     [m_window setFrame:NSMakeRect(frame.origin.x, frame.origin.y, frame.size.width, frame.size.height) display:YES];
197 }
198
199 void PlatformWebView::didInitializeClients()
200 {
201     // Set a temporary 1x1 window frame to force a WindowAndViewFramesChanged notification. <rdar://problem/13380145>
202     forceWindowFramesChanged();
203 }
204
205 void PlatformWebView::addChromeInputField()
206 {
207     NSTextField* textField = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 20)];
208     textField.tag = 1;
209     [[m_window contentView] addSubview:textField];
210     [textField release];
211
212     [textField setNextKeyView:m_view];
213     [m_view setNextKeyView:textField];
214 }
215
216 void PlatformWebView::removeChromeInputField()
217 {
218     NSView* textField = [[m_window contentView] viewWithTag:1];
219     if (textField) {
220         [textField removeFromSuperview];
221         makeWebViewFirstResponder();
222     }
223 }
224
225 void PlatformWebView::makeWebViewFirstResponder()
226 {
227     [m_window makeFirstResponder:m_view];
228 }
229
230 WKRetainPtr<WKImageRef> PlatformWebView::windowSnapshotImage()
231 {
232     [m_view display];
233     RetainPtr<CGImageRef> windowSnapshotImage = adoptCF(CGWindowListCreateImage(CGRectNull, kCGWindowListOptionIncludingWindow, [m_window windowNumber], kCGWindowImageBoundsIgnoreFraming | kCGWindowImageShouldBeOpaque));
234
235     // windowSnapshotImage will be in GenericRGB, as we've set the main display's color space to GenericRGB.
236     return adoptWK(WKImageCreateFromCGImage(windowSnapshotImage.get(), 0));
237 }
238
239 bool PlatformWebView::viewSupportsOptions(WKDictionaryRef options) const
240 {
241     WKRetainPtr<WKStringRef> useThreadedScrollingKey(AdoptWK, WKStringCreateWithUTF8CString("ThreadedScrolling"));
242     WKTypeRef useThreadedScrollingValue = WKDictionaryGetItemForKey(options, useThreadedScrollingKey.get());
243     bool useThreadedScrolling = useThreadedScrollingValue && WKBooleanGetValue(static_cast<WKBooleanRef>(useThreadedScrollingValue));
244
245     return useThreadedScrolling == [(TestRunnerWKView *)m_view useThreadedScrolling];
246 }
247
248 void PlatformWebView::changeWindowScaleIfNeeded(float newScale)
249 {
250     CGFloat currentScale = [m_window backingScaleFactor];
251     if (currentScale == newScale)
252         return;
253     [m_window _setWindowResolution:newScale displayIfChanged:YES];
254     // Instead of re-constructing the current window, let's fake resize it to ensure that the scale change gets picked up.
255     forceWindowFramesChanged();
256     // Changing the scaling factor on the window does not trigger NSWindowDidChangeBackingPropertiesNotification. We need to send the notification manually.
257     RetainPtr<NSMutableDictionary> notificationUserInfo = adoptNS([[NSMutableDictionary alloc] initWithCapacity:1]);
258     [notificationUserInfo setObject:[NSNumber numberWithDouble:currentScale] forKey:NSBackingPropertyOldScaleFactorKey];
259     [[NSNotificationCenter defaultCenter] postNotificationName:NSWindowDidChangeBackingPropertiesNotification object:m_window userInfo:notificationUserInfo.get()];
260 }
261
262 void PlatformWebView::forceWindowFramesChanged()
263 {
264     WKRect wkFrame = windowFrame();
265     [m_window setFrame:NSMakeRect(0, 0, 1, 1) display:YES];
266     setWindowFrame(wkFrame);
267 }
268
269 } // namespace WTR