Multiple File Input Icon Set Regardless of File List
[WebKit-https.git] / Tools / DumpRenderTree / mac / UIDelegate.mm
1 /*
2  * Copyright (C) 2006. 2007 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  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer. 
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution. 
13  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #import "config.h"
30 #import "UIDelegate.h"
31
32 #import "DumpRenderTree.h"
33 #import "DumpRenderTreeDraggingInfo.h"
34 #import "EventSendingController.h"
35 #import "MockWebNotificationProvider.h"
36 #import "TestRunner.h"
37
38 #import <WebKit/WebApplicationCache.h>
39 #import <WebKit/WebFramePrivate.h>
40 #import <WebKit/WebHTMLViewPrivate.h>
41 #import <WebKit/WebDatabaseManagerPrivate.h>
42 #import <WebKit/WebQuotaManager.h>
43 #import <WebKit/WebSecurityOriginPrivate.h>
44 #import <WebKit/WebUIDelegatePrivate.h>
45 #import <WebKit/WebView.h>
46 #import <WebKit/WebViewPrivate.h>
47 #import <wtf/Assertions.h>
48
49 #if !PLATFORM(IOS_FAMILY)
50 DumpRenderTreeDraggingInfo *draggingInfo = nil;
51 #endif
52
53 @implementation UIDelegate
54
55 - (void)resetWindowOrigin
56 {
57     windowOrigin = NSZeroPoint;
58 }
59
60 - (void)resetToConsistentStateBeforeTesting:(const TestOptions&)options
61 {
62     m_enableDragDestinationActionLoad = options.enableDragDestinationActionLoad;
63 }
64
65 - (void)webView:(WebView *)sender setFrame:(NSRect)frame
66 {
67     // FIXME: Do we need to resize an NSWindow too?
68     windowOrigin = frame.origin;
69     [sender setFrameSize:frame.size];
70 }
71
72 - (NSRect)webViewFrame:(WebView *)sender
73 {
74     NSSize size = [sender frame].size;
75     return NSMakeRect(windowOrigin.x, windowOrigin.y, size.width, size.height);
76 }
77
78 - (void)webView:(WebView *)sender addMessageToConsole:(NSDictionary *)dictionary withSource:(NSString *)source
79 {
80     if (done)
81         return;
82
83     NSString *message = [dictionary objectForKey:@"message"];
84     NSNumber *lineNumber = [dictionary objectForKey:@"lineNumber"];
85
86     NSRange range = [message rangeOfString:@"file://"];
87     if (range.location != NSNotFound)
88         message = [[message substringToIndex:range.location] stringByAppendingString:[[message substringFromIndex:NSMaxRange(range)] lastPathComponent]];
89
90     auto out = gTestRunner->dumpJSConsoleLogInStdErr() ? stderr : stdout;
91     fprintf(out, "CONSOLE MESSAGE: ");
92     if ([lineNumber intValue])
93         fprintf(out, "line %d: ", [lineNumber intValue]);
94     fprintf(out, "%s\n", [message UTF8String]);
95 }
96
97 - (void)modalWindowWillClose:(NSNotification *)notification
98 {
99 #if !PLATFORM(IOS_FAMILY)
100     [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowWillCloseNotification object:nil];
101     [NSApp abortModal];
102 #endif
103 }
104
105 - (void)webViewRunModal:(WebView *)sender
106 {
107 #if !PLATFORM(IOS_FAMILY)
108     gTestRunner->setWindowIsKey(false);
109     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(modalWindowWillClose:) name:NSWindowWillCloseNotification object:nil];
110     [NSApp runModalForWindow:[sender window]];
111     gTestRunner->setWindowIsKey(true);
112 #endif
113 }
114
115 - (void)webView:(WebView *)sender runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame
116 {
117     if (!done) {
118         printf("ALERT: %s\n", [message UTF8String]);
119         fflush(stdout);
120     }
121 }
122
123 - (BOOL)webView:(WebView *)sender runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame
124 {
125     if (!done)
126         printf("CONFIRM: %s\n", [message UTF8String]);
127     return YES;
128 }
129
130 - (NSString *)webView:(WebView *)sender runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WebFrame *)frame
131 {
132     if (!done)
133         printf("PROMPT: %s, default text: %s\n", [prompt UTF8String], [defaultText UTF8String]);
134     return defaultText;
135 }
136
137 - (BOOL)webView:(WebView *)c runBeforeUnloadConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame
138 {
139     if (!done)
140         printf("CONFIRM NAVIGATION: %s\n", [message UTF8String]);
141     
142     return !gTestRunner->shouldStayOnPageAfterHandlingBeforeUnload();
143 }
144
145
146 #if !PLATFORM(IOS_FAMILY)
147 - (void)webView:(WebView *)sender dragImage:(NSImage *)anImage at:(NSPoint)viewLocation offset:(NSSize)initialOffset event:(NSEvent *)event pasteboard:(NSPasteboard *)pboard source:(id)sourceObj slideBack:(BOOL)slideFlag forView:(NSView *)view
148 {
149      assert(!draggingInfo);
150      draggingInfo = [[DumpRenderTreeDraggingInfo alloc] initWithImage:anImage offset:initialOffset pasteboard:pboard source:sourceObj];
151      [sender draggingUpdated:draggingInfo];
152      [EventSendingController replaySavedEvents];
153 }
154 #endif
155
156 - (void)webViewFocus:(WebView *)webView
157 {
158     gTestRunner->setWindowIsKey(true);
159 }
160
161 - (void)webViewUnfocus:(WebView *)webView
162 {
163     gTestRunner->setWindowIsKey(false);
164 }
165
166 - (WebView *)webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request
167 {
168     if (!gTestRunner->canOpenWindows())
169         return nil;
170     
171     // Make sure that waitUntilDone has been called.
172     ASSERT(gTestRunner->waitToDump());
173
174     WebView *webView = createWebViewAndOffscreenWindow();
175     
176     if (gTestRunner->newWindowsCopyBackForwardList())
177         [webView _loadBackForwardListFromOtherView:sender];
178     
179     return [webView autorelease];
180 }
181
182 - (void)webViewClose:(WebView *)sender
183 {
184     NSWindow* window = [sender window];
185  
186     if (gTestRunner->callCloseOnWebViews())
187         [sender close];
188     
189     [window close];
190 }
191
192 - (void)webView:(WebView *)sender frame:(WebFrame *)frame exceededDatabaseQuotaForSecurityOrigin:(WebSecurityOrigin *)origin database:(NSString *)databaseIdentifier
193 {
194     if (!done && gTestRunner->dumpDatabaseCallbacks()) {
195         printf("UI DELEGATE DATABASE CALLBACK: exceededDatabaseQuotaForSecurityOrigin:{%s, %s, %i} database:%s\n", [[origin protocol] UTF8String], [[origin host] UTF8String], 
196             [origin port], [databaseIdentifier UTF8String]);
197     }
198
199     NSDictionary *databaseDetails = [[WebDatabaseManager sharedWebDatabaseManager] detailsForDatabase:databaseIdentifier withOrigin:origin];
200     unsigned long long expectedSize = [[databaseDetails objectForKey:WebDatabaseExpectedSizeKey] unsignedLongLongValue];
201     unsigned long long defaultQuota = 5 * 1024 * 1024;
202     double testDefaultQuota = gTestRunner->databaseDefaultQuota();
203     if (testDefaultQuota >= 0)
204         defaultQuota = testDefaultQuota;
205
206     unsigned long long newQuota = defaultQuota;
207
208     double maxQuota = gTestRunner->databaseMaxQuota();
209     if (maxQuota >= 0) {
210         if (defaultQuota < expectedSize && expectedSize <= maxQuota) {
211             newQuota = expectedSize;
212             printf("UI DELEGATE DATABASE CALLBACK: increased quota to %llu\n", newQuota);
213         }
214     }
215     [[origin databaseQuotaManager] setQuota:newQuota];
216 }
217
218 - (void)webView:(WebView *)sender exceededApplicationCacheOriginQuotaForSecurityOrigin:(WebSecurityOrigin *)origin totalSpaceNeeded:(NSUInteger)totalSpaceNeeded
219 {
220     if (!done && gTestRunner->dumpApplicationCacheDelegateCallbacks()) {
221         // For example, numbers from 30000 - 39999 will output as 30000.
222         // Rounding up or down not really matter for these tests. It's
223         // sufficient to just get a range of 10000 to determine if we were
224         // above or below a threshold.
225         unsigned long truncatedSpaceNeeded = static_cast<unsigned long>((totalSpaceNeeded / 10000) * 10000);
226         printf("UI DELEGATE APPLICATION CACHE CALLBACK: exceededApplicationCacheOriginQuotaForSecurityOrigin:{%s, %s, %i} totalSpaceNeeded:~%lu\n",
227             [[origin protocol] UTF8String], [[origin host] UTF8String], [origin port], truncatedSpaceNeeded);
228     }
229
230     if (gTestRunner->disallowIncreaseForApplicationCacheQuota())
231         return;
232
233     static const unsigned long long defaultOriginQuota = [WebApplicationCache defaultOriginQuota];
234     [[origin applicationCacheQuotaManager] setQuota:defaultOriginQuota];
235 }
236
237 - (void)webView:(WebView *)sender setStatusText:(NSString *)text
238 {
239     if (!done && gTestRunner->dumpStatusCallbacks())
240         printf("UI DELEGATE STATUS CALLBACK: setStatusText:%s\n", [text UTF8String]);
241 }
242
243 - (void)webView:(WebView *)webView decidePolicyForGeolocationRequestFromOrigin:(WebSecurityOrigin *)origin frame:(WebFrame *)frame listener:(id<WebAllowDenyPolicyListener>)listener
244 {
245     if (!gTestRunner->isGeolocationPermissionSet()) {
246         if (!m_pendingGeolocationPermissionListeners)
247             m_pendingGeolocationPermissionListeners = [[NSMutableSet set] retain];
248         [m_pendingGeolocationPermissionListeners addObject:listener];
249         return;
250     }
251
252     if (gTestRunner->geolocationPermission())
253         [listener allow];
254     else
255         [listener deny];
256 }
257
258 - (void)didSetMockGeolocationPermission
259 {
260     ASSERT(gTestRunner->isGeolocationPermissionSet());
261     if (m_pendingGeolocationPermissionListeners && !m_timer)
262         m_timer = [NSTimer scheduledTimerWithTimeInterval:0 target:self selector:@selector(timerFired) userInfo:0 repeats:NO];
263 }
264
265 - (int)numberOfPendingGeolocationPermissionRequests
266 {
267     if (!m_pendingGeolocationPermissionListeners)
268         return 0;
269     return [m_pendingGeolocationPermissionListeners count];
270 }
271
272
273 - (void)timerFired
274 {
275     m_timer = 0;
276     NSEnumerator* enumerator = [m_pendingGeolocationPermissionListeners objectEnumerator];
277     id<WebAllowDenyPolicyListener> listener;
278     while ((listener = [enumerator nextObject])) {
279         if (gTestRunner->geolocationPermission())
280             [listener allow];
281         else
282             [listener deny];
283     }
284     [m_pendingGeolocationPermissionListeners removeAllObjects];
285     [m_pendingGeolocationPermissionListeners release];
286     m_pendingGeolocationPermissionListeners = nil;
287 }
288
289 - (BOOL)webView:(WebView *)sender shouldHaltPlugin:(DOMNode *)pluginNode
290 {
291     return NO;
292 }
293
294 - (BOOL)webView:(WebView *)webView supportsFullScreenForElement:(DOMElement*)element withKeyboard:(BOOL)withKeyboard
295 {
296 #if PLATFORM(IOS_FAMILY)
297     return NO;
298 #else
299     return YES;
300 #endif
301 }
302
303 #if ENABLE(FULLSCREEN_API)
304 - (void)enterFullScreenWithListener:(NSObject<WebKitFullScreenListener>*)listener
305 {
306     [listener webkitWillEnterFullScreen];
307     [listener webkitDidEnterFullScreen];
308 }
309
310 - (void)webView:(WebView *)webView enterFullScreenForElement:(DOMElement*)element listener:(NSObject<WebKitFullScreenListener>*)listener
311 {
312     if (!gTestRunner->hasCustomFullScreenBehavior())
313         [self performSelector:@selector(enterFullScreenWithListener:) withObject:listener afterDelay:0];
314 }
315
316 - (void)exitFullScreenWithListener:(NSObject<WebKitFullScreenListener>*)listener
317 {
318     [listener webkitWillExitFullScreen];
319     [listener webkitDidExitFullScreen];
320 }
321
322 - (void)webView:(WebView *)webView exitFullScreenForElement:(DOMElement*)element listener:(NSObject<WebKitFullScreenListener>*)listener
323 {
324     if (!gTestRunner->hasCustomFullScreenBehavior())
325         [self performSelector:@selector(exitFullScreenWithListener:) withObject:listener afterDelay:0];
326 }
327
328 - (void)webView:(WebView *)sender closeFullScreenWithListener:(NSObject<WebKitFullScreenListener>*)listener
329 {
330     [listener webkitWillExitFullScreen];
331     [listener webkitDidExitFullScreen];
332 }
333 #endif
334
335 - (BOOL)webView:(WebView *)webView didPressMissingPluginButton:(DOMElement *)element
336 {
337     if (!done)
338         printf("MISSING PLUGIN BUTTON PRESSED\n");
339     return TRUE;
340 }
341
342 - (void)webView:(WebView *)webView decidePolicyForNotificationRequestFromOrigin:(WebSecurityOrigin *)origin listener:(id<WebAllowDenyPolicyListener>)listener
343 {
344     MockWebNotificationProvider *provider = (MockWebNotificationProvider *)[webView _notificationProvider];
345     switch ([provider policyForOrigin:origin]) {
346     case WebNotificationPermissionAllowed:
347         [listener allow];
348         break;
349     case WebNotificationPermissionDenied:
350         [listener deny];
351         break;
352     case WebNotificationPermissionNotAllowed:
353         [provider setWebNotificationOrigin:[origin stringValue] permission:YES];
354         [listener allow];
355         break;
356     }
357 }
358
359 - (NSData *)webCryptoMasterKeyForWebView:(WebView *)sender
360 {
361     // Any 128 bit key would do, all we need for testing is to implement the callback.
362     return [NSData dataWithBytes:"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" length:16];
363 }
364
365 - (NSString *)signedPublicKeyAndChallengeStringForWebView:(WebView *)sender
366 {
367     // Any fake response would do, all we need for testing is to implement the callback.
368     return @"MIHFMHEwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAnX0TILJrOMUue%2BPtwBRE6XfV%0AWtKQbsshxk5ZhcUwcwyvcnIq9b82QhJdoACdD34rqfCAIND46fXKQUnb0mvKzQID%0AAQABFhFNb3ppbGxhSXNNeUZyaWVuZDANBgkqhkiG9w0BAQQFAANBAAKv2Eex2n%2FS%0Ar%2F7iJNroWlSzSMtTiQTEB%2BADWHGj9u1xrUrOilq%2Fo2cuQxIfZcNZkYAkWP4DubqW%0Ai0%2F%2FrgBvmco%3D";
369 }
370
371 - (void)webView:(WebView *)sender runOpenPanelForFileButtonWithResultListener:(id<WebOpenPanelResultListener>)resultListener allowMultipleFiles:(BOOL)allowMultipleFiles
372 {
373     printf("OPEN FILE PANEL\n");
374
375     auto& openPanelFiles = gTestRunner->openPanelFiles();
376     if (openPanelFiles.empty()) {
377         [resultListener cancel];
378         return;
379     }
380
381     NSURL *baseURL = [NSURL URLWithString:[NSString stringWithUTF8String:gTestRunner->testURL().c_str()]];
382     auto filePaths = adoptNS([[NSMutableArray alloc] initWithCapacity:openPanelFiles.size()]);
383     for (auto& filePath : openPanelFiles) {
384         NSURL *fileURL = [NSURL fileURLWithPath:[NSString stringWithUTF8String:filePath.c_str()] relativeToURL:baseURL];
385         [filePaths addObject:fileURL.path];
386     }
387
388 #if PLATFORM(IOS_FAMILY)
389     NSURL *firstURL = [NSURL fileURLWithPath:[NSString stringWithUTF8String:openPanelFiles[0].c_str()] relativeToURL:baseURL];
390     NSString *displayString = firstURL.lastPathComponent;
391     const std::vector<char>& iconData = gTestRunner->openPanelFilesMediaIcon();
392     CGImageRef imageRef;
393     if (!iconData.empty()) {
394         RetainPtr<CFDataRef> dataRef = adoptCF(CFDataCreate(nullptr, (unsigned char *)iconData.data(), iconData.size()));
395         RetainPtr<CGDataProviderRef> imageProviderRef = adoptCF(CGDataProviderCreateWithCFData(dataRef.get()));
396         imageRef = CGImageCreateWithJPEGDataProvider(imageProviderRef.get(), nullptr, true, kCGRenderingIntentDefault);
397     }
398 #endif
399
400     if (allowMultipleFiles) {
401 #if PLATFORM(IOS_FAMILY)
402         [resultListener chooseFilenames:filePaths.get() displayString:displayString iconImage:imageRef];
403 #else
404         [resultListener chooseFilenames:filePaths.get()];
405 #endif
406         return;
407     }
408
409 #if PLATFORM(IOS_FAMILY)
410     [resultListener chooseFilename:[filePaths firstObject] displayString:displayString iconImage:imageRef];
411 #else
412     [resultListener chooseFilename:[filePaths firstObject]];
413 #endif
414 }
415
416 #if !PLATFORM(IOS_FAMILY)
417
418 - (NSUInteger)webView:(WebView *)webView dragDestinationActionMaskForDraggingInfo:(id <NSDraggingInfo>)draggingInfo
419 {
420     WebDragDestinationAction actions = WebDragDestinationActionAny;
421     if (!m_enableDragDestinationActionLoad)
422         actions &= ~WebDragDestinationActionLoad;
423     return actions;
424 }
425
426 #endif
427
428 - (void)dealloc
429 {
430 #if !PLATFORM(IOS_FAMILY)
431     [draggingInfo release];
432     draggingInfo = nil;
433 #endif
434     [m_pendingGeolocationPermissionListeners release];
435     m_pendingGeolocationPermissionListeners = nil;
436
437     [super dealloc];
438 }
439
440 @end