2 * Copyright (C) 2010 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.
26 #import "WK2BrowserWindowController.h"
30 #import "AppDelegate.h"
31 #import <WebKit/WKFrameInfo.h>
32 #import <WebKit/WKNavigationDelegate.h>
33 #import <WebKit/WKUIDelegate.h>
34 #import <WebKit/WKWebView.h>
35 #import <WebKit/WKWebViewPrivate.h>
37 static void* keyValueObservingContext = &keyValueObservingContext;
38 static NSString * const WebKit2UseRemoteLayerTreeDrawingAreaKey = @"WebKit2UseRemoteLayerTreeDrawingArea";
39 static NSString * const WebKit2SubpixelCSSOMElementMetricsEnabledKey = @"WebKitSubpixelCSSOMElementMetricsEnabled";
41 @interface WK2BrowserWindowController () <WKNavigationDelegate, WKUIDelegate>
44 @implementation WK2BrowserWindowController {
51 _webView = [[WKWebView alloc] initWithFrame:[containerView bounds]];
53 _webView.allowsMagnification = YES;
54 _webView.allowsBackForwardNavigationGestures = YES;
56 [_webView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
57 [containerView addSubview:_webView];
59 [progressIndicator bind:NSHiddenBinding toObject:_webView withKeyPath:@"loading" options:@{ NSValueTransformerNameBindingOption : NSNegateBooleanTransformerName }];
60 [progressIndicator bind:NSValueBinding toObject:_webView withKeyPath:@"estimatedProgress" options:nil];
62 [_webView addObserver:self forKeyPath:@"title" options:0 context:keyValueObservingContext];
63 [_webView addObserver:self forKeyPath:@"URL" options:0 context:keyValueObservingContext];
65 _webView.navigationDelegate = self;
66 _webView.UIDelegate = self;
73 [_webView removeObserver:self forKeyPath:@"title"];
74 [_webView removeObserver:self forKeyPath:@"URL"];
76 [progressIndicator unbind:NSHiddenBinding];
77 [progressIndicator unbind:NSValueBinding];
84 - (IBAction)fetch:(id)sender
86 [urlText setStringValue:[self addProtocolIfNecessary:[urlText stringValue]]];
88 [_webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[urlText stringValue]]]];
91 - (IBAction)showHideWebView:(id)sender
93 BOOL hidden = ![_webView isHidden];
95 [_webView setHidden:hidden];
98 - (IBAction)removeReinsertWebView:(id)sender
100 if ([_webView window]) {
102 [_webView removeFromSuperview];
104 [containerView addSubview:_webView];
109 - (BOOL)validateMenuItem:(NSMenuItem *)menuItem
111 SEL action = [menuItem action];
113 if (action == @selector(zoomIn:))
114 return [self canZoomIn];
115 if (action == @selector(zoomOut:))
116 return [self canZoomOut];
117 if (action == @selector(resetZoom:))
118 return [self canResetZoom];
120 // Disabled until missing WK2 functionality is exposed via API/SPI.
121 if (action == @selector(dumpSourceToConsole:)
122 || action == @selector(find:))
125 if (action == @selector(showHideWebView:))
126 [menuItem setTitle:[_webView isHidden] ? @"Show Web View" : @"Hide Web View"];
127 else if (action == @selector(removeReinsertWebView:))
128 [menuItem setTitle:[_webView window] ? @"Remove Web View" : @"Insert Web View"];
129 else if (action == @selector(toggleZoomMode:))
130 [menuItem setState:_zoomTextOnly ? NSOnState : NSOffState];
131 else if ([menuItem action] == @selector(togglePaginationMode:))
132 [menuItem setState:[self isPaginated] ? NSOnState : NSOffState];
133 else if ([menuItem action] == @selector(toggleTransparentWindow:))
134 [menuItem setState:[[self window] isOpaque] ? NSOffState : NSOnState];
135 else if ([menuItem action] == @selector(toggleUISideCompositing:))
136 [menuItem setState:[self isUISideCompositingEnabled] ? NSOnState : NSOffState];
137 else if ([menuItem action] == @selector(toggleSubpixelCSSOMElementMetricsEnabled:))
138 [menuItem setState:[self isSubpixelCSSOMElementMetricsEnabled] ? NSOnState : NSOffState];
143 - (IBAction)reload:(id)sender
148 - (IBAction)forceRepaint:(id)sender
150 [_webView setNeedsDisplay:YES];
153 - (IBAction)goBack:(id)sender
158 - (IBAction)goForward:(id)sender
160 [_webView goForward];
163 - (IBAction)toggleZoomMode:(id)sender
167 double currentTextZoom = _webView._textZoomFactor;
168 _webView._textZoomFactor = 1;
169 _webView._pageZoomFactor = currentTextZoom;
172 double currentPageZoom = _webView._pageZoomFactor;
173 _webView._textZoomFactor = currentPageZoom;
174 _webView._pageZoomFactor = 1;
178 - (IBAction)resetZoom:(id)sender
180 if (![self canResetZoom])
184 _webView._textZoomFactor = 1;
186 _webView._pageZoomFactor = 1;
191 return _zoomTextOnly ? (_webView._textZoomFactor != 1) : (_webView._pageZoomFactor != 1);
194 - (IBAction)dumpSourceToConsole:(id)sender
198 - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
200 SEL action = item.action;
202 if (action == @selector(goBack:) || action == @selector(goForward:))
203 return [_webView validateUserInterfaceItem:item];
208 - (void)validateToolbar
210 [toolbar validateVisibleItems];
213 - (BOOL)windowShouldClose:(id)sender
218 - (void)windowWillClose:(NSNotification *)notification
220 [(BrowserAppDelegate *)[NSApp delegate] browserWindowWillClose:[self window]];
224 - (void)applicationTerminating
228 #define DefaultMinimumZoomFactor (.5)
229 #define DefaultMaximumZoomFactor (3.0)
230 #define DefaultZoomFactorRatio (1.2)
232 - (CGFloat)currentZoomFactor
234 return _zoomTextOnly ? _webView._textZoomFactor : _webView._pageZoomFactor;
237 - (void)setCurrentZoomFactor:(CGFloat)factor
240 _webView._textZoomFactor = factor;
242 _webView._pageZoomFactor = factor;
247 return self.currentZoomFactor * DefaultZoomFactorRatio < DefaultMaximumZoomFactor;
250 - (void)zoomIn:(id)sender
255 self.currentZoomFactor *= DefaultZoomFactorRatio;
260 return self.currentZoomFactor / DefaultZoomFactorRatio > DefaultMinimumZoomFactor;
263 - (void)zoomOut:(id)sender
268 self.currentZoomFactor /= DefaultZoomFactorRatio;
273 return _webView._paginationMode != _WKPaginationModeUnpaginated;
276 - (IBAction)togglePaginationMode:(id)sender
278 if (self.isPaginated)
279 _webView._paginationMode = _WKPaginationModeUnpaginated;
281 _webView._paginationMode = _WKPaginationModeLeftToRight;
282 _webView._pageLength = _webView.bounds.size.width / 2;
283 _webView._gapBetweenPages = 10;
287 - (IBAction)toggleTransparentWindow:(id)sender
289 BOOL isTransparent = _webView._drawsTransparentBackground;
290 isTransparent = !isTransparent;
292 [[self window] setOpaque:!isTransparent];
293 [[self window] setHasShadow:!isTransparent];
295 _webView._drawsTransparentBackground = isTransparent;
297 [[self window] display];
300 - (BOOL)isSubpixelCSSOMElementMetricsEnabled
302 return [[NSUserDefaults standardUserDefaults] boolForKey:WebKit2SubpixelCSSOMElementMetricsEnabledKey];
305 - (IBAction)toggleSubpixelCSSOMElementMetricsEnabled:(id)sender
307 [[NSUserDefaults standardUserDefaults] setBool:![self isSubpixelCSSOMElementMetricsEnabled] forKey:WebKit2SubpixelCSSOMElementMetricsEnabledKey];
310 - (BOOL)isUISideCompositingEnabled
312 return [[NSUserDefaults standardUserDefaults] boolForKey:WebKit2UseRemoteLayerTreeDrawingAreaKey];
315 - (IBAction)toggleUISideCompositing:(id)sender
317 NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
318 BOOL newValue = ![userDefaults boolForKey:WebKit2UseRemoteLayerTreeDrawingAreaKey];
319 [userDefaults setBool:newValue forKey:WebKit2UseRemoteLayerTreeDrawingAreaKey];
322 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
324 if (context != keyValueObservingContext || object != _webView)
327 if ([keyPath isEqualToString:@"title"])
328 self.window.title = [_webView.title stringByAppendingFormat:@" [WK2, %d]", _webView._webProcessIdentifier];
329 else if ([keyPath isEqualToString:@"URL"])
330 [self updateTextFieldFromURL:_webView.URL];
333 - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)())completionHandler
335 NSAlert* alert = [[NSAlert alloc] init];
337 [alert setMessageText:[NSString stringWithFormat:@"JavaScript alert dialog from %@.", [frame.request.URL absoluteString]]];
338 [alert setInformativeText:message];
339 [alert addButtonWithTitle:@"OK"];
341 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
342 [alert beginSheetModalForWindow:self.window completionHandler:^void (NSModalResponse response) {
349 - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler
351 NSAlert* alert = [[NSAlert alloc] init];
353 [alert setMessageText:[NSString stringWithFormat:@"JavaScript confirm dialog from %@.", [frame.request.URL absoluteString]]];
354 [alert setInformativeText:message];
356 [alert addButtonWithTitle:@"OK"];
357 [alert addButtonWithTitle:@"Cancel"];
359 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
360 [alert beginSheetModalForWindow:self.window completionHandler:^void (NSModalResponse response) {
361 completionHandler(response == NSAlertFirstButtonReturn);
367 - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString *result))completionHandler
369 NSAlert* alert = [[NSAlert alloc] init];
371 [alert setMessageText:[NSString stringWithFormat:@"JavaScript prompt dialog from %@.", [frame.request.URL absoluteString]]];
372 [alert setInformativeText:prompt];
374 [alert addButtonWithTitle:@"OK"];
375 [alert addButtonWithTitle:@"Cancel"];
377 NSTextField* input = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 200, 24)];
378 [input setStringValue:defaultText];
379 [alert setAccessoryView:input];
381 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
382 [alert beginSheetModalForWindow:self.window completionHandler:^void (NSModalResponse response) {
383 [input validateEditing];
384 completionHandler(response == NSAlertFirstButtonReturn ? [input stringValue] : nil);
390 - (void)updateTextFieldFromURL:(NSURL *)URL
395 if (!URL.absoluteString.length)
398 urlText.stringValue = [URL absoluteString];
401 - (void)loadURLString:(NSString *)urlString
403 // FIXME: We shouldn't have to set the url text here.
404 [urlText setStringValue:urlString];
408 - (IBAction)performFindPanelAction:(id)sender
410 [findPanelWindow makeKeyAndOrderFront:sender];
413 - (IBAction)find:(id)sender
417 #pragma mark WKNavigationDelegate
419 - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
421 LOG(@"decidePolicyForNavigationResponse");
422 decisionHandler(WKNavigationResponsePolicyAllow);
425 - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation
427 LOG(@"didStartProvisionalNavigation: %@", navigation);
430 - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation
432 LOG(@"didReceiveServerRedirectForProvisionalNavigation: %@", navigation);
435 - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error
437 LOG(@"didFailProvisionalNavigation: %@navigation, error: %@", navigation, error);
440 - (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation
442 LOG(@"didCommitNavigation: %@", navigation);
445 - (void)webView:(WKWebView *)webView didFinishLoadingNavigation:(WKNavigation *)navigation
447 LOG(@"didFinishLoadingNavigation: %@", navigation);
450 - (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error
452 LOG(@"didFailNavigation: %@, error %@", navigation, error);
457 #endif // WK_API_ENABLED