Add simple line layout toggle to MiniBrowser
[WebKit-https.git] / Tools / MiniBrowser / mac / WK2BrowserWindowController.m
1 /*
2  * Copyright (C) 2010-2016 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 "WK2BrowserWindowController.h"
27
28 #if WK_API_ENABLED
29
30 #import "AppDelegate.h"
31 #import "SettingsController.h"
32 #import <WebKit/WKFrameInfo.h>
33 #import <WebKit/WKNavigationActionPrivate.h>
34 #import <WebKit/WKNavigationDelegate.h>
35 #import <WebKit/WKPreferencesPrivate.h>
36 #import <WebKit/WKUIDelegate.h>
37 #import <WebKit/WKWebViewConfigurationPrivate.h>
38 #import <WebKit/WKWebViewPrivate.h>
39 #import <WebKit/WKWebsiteDataStorePrivate.h>
40 #import <WebKit/WebNSURLExtras.h>
41 #import <WebKit/_WKIconLoadingDelegate.h>
42 #import <WebKit/_WKLinkIconParameters.h>
43 #import <WebKit/_WKUserInitiatedAction.h>
44
45 static void* keyValueObservingContext = &keyValueObservingContext;
46 static const int testHeaderBannerHeight = 42;
47 static const int testFooterBannerHeight = 58;
48
49 @interface WK2BrowserWindowController () <NSTextFinderBarContainer, WKNavigationDelegate, WKUIDelegate, _WKIconLoadingDelegate>
50 @end
51
52 @implementation WK2BrowserWindowController {
53     WKWebViewConfiguration *_configuration;
54     WKWebView *_webView;
55     BOOL _zoomTextOnly;
56     BOOL _isPrivateBrowsingWindow;
57
58     BOOL _useShrinkToFit;
59
60     NSTextFinder *_textFinder;
61     NSView *_textFindBarView;
62     BOOL _findBarVisible;
63 }
64
65 - (void)awakeFromNib
66 {
67     _webView = [[WKWebView alloc] initWithFrame:[containerView bounds] configuration:_configuration];
68     [self didChangeSettings];
69
70     _webView.allowsMagnification = YES;
71     _webView.allowsBackForwardNavigationGestures = YES;
72     _webView._editable = self.isEditable;
73
74     [_webView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
75     [containerView addSubview:_webView];
76
77     [progressIndicator bind:NSHiddenBinding toObject:_webView withKeyPath:@"loading" options:@{ NSValueTransformerNameBindingOption : NSNegateBooleanTransformerName }];
78     [progressIndicator bind:NSValueBinding toObject:_webView withKeyPath:@"estimatedProgress" options:nil];
79
80     [_webView addObserver:self forKeyPath:@"title" options:0 context:keyValueObservingContext];
81     [_webView addObserver:self forKeyPath:@"URL" options:0 context:keyValueObservingContext];
82
83     _webView.navigationDelegate = self;
84     _webView.UIDelegate = self;
85
86     // This setting installs the new WK2 Icon Loading Delegate and tests that mechanism by
87     // telling WebKit to load every icon referenced by the page.
88     if ([[SettingsController shared] loadsAllSiteIcons])
89         _webView._iconLoadingDelegate = self;
90     
91     _webView._observedRenderingProgressEvents = _WKRenderingProgressEventFirstLayout
92         | _WKRenderingProgressEventFirstVisuallyNonEmptyLayout
93         | _WKRenderingProgressEventFirstPaintWithSignificantArea
94         | _WKRenderingProgressEventFirstLayoutAfterSuppressedIncrementalRendering
95         | _WKRenderingProgressEventFirstPaintAfterSuppressedIncrementalRendering;
96
97     _zoomTextOnly = NO;
98
99     _textFinder = [[NSTextFinder alloc] init];
100     _textFinder.incrementalSearchingEnabled = YES;
101     _textFinder.incrementalSearchingShouldDimContentView = YES;
102     _textFinder.client = _webView;
103     _textFinder.findBarContainer = self;
104 }
105
106 - (instancetype)initWithConfiguration:(WKWebViewConfiguration *)configuration
107 {
108     if (!(self = [super initWithWindowNibName:@"BrowserWindow"]))
109         return nil;
110
111     _configuration = [configuration copy];
112     _isPrivateBrowsingWindow = !_configuration.websiteDataStore.isPersistent;
113
114     return self;
115 }
116
117 - (void)dealloc
118 {
119     [_webView removeObserver:self forKeyPath:@"title"];
120     [_webView removeObserver:self forKeyPath:@"URL"];
121     
122     [progressIndicator unbind:NSHiddenBinding];
123     [progressIndicator unbind:NSValueBinding];
124
125     [_textFinder release];
126
127     [_webView release];
128     [_configuration release];
129
130     [super dealloc];
131 }
132
133 - (IBAction)fetch:(id)sender
134 {
135     [urlText setStringValue:[self addProtocolIfNecessary:[urlText stringValue]]];
136
137     [_webView loadRequest:[NSURLRequest requestWithURL:[NSURL _webkit_URLWithUserTypedString:[urlText stringValue]]]];
138 }
139
140 - (IBAction)setPageScale:(id)sender
141 {
142     CGFloat scale = [self pageScaleForMenuItemTag:[sender tag]];
143     [_webView _setPageScale:scale withOrigin:CGPointZero];
144 }
145
146 - (CGFloat)viewScaleForMenuItemTag:(NSInteger)tag
147 {
148     if (tag == 1)
149         return 1;
150     if (tag == 2)
151         return 0.75;
152     if (tag == 3)
153         return 0.5;
154     if (tag == 4)
155         return 0.25;
156
157     return 1;
158 }
159
160 - (IBAction)setViewScale:(id)sender
161 {
162     CGFloat scale = [self viewScaleForMenuItemTag:[sender tag]];
163     CGFloat oldScale = [_webView _viewScale];
164
165     if (scale == oldScale)
166         return;
167
168     [_webView _setLayoutMode:_WKLayoutModeDynamicSizeComputedFromViewScale];
169
170     NSRect oldFrame = self.window.frame;
171     NSSize newFrameSize = NSMakeSize(oldFrame.size.width * (scale / oldScale), oldFrame.size.height * (scale / oldScale));
172     [self.window setFrame:NSMakeRect(oldFrame.origin.x, oldFrame.origin.y - (newFrameSize.height - oldFrame.size.height), newFrameSize.width, newFrameSize.height) display:NO animate:NO];
173
174     [_webView _setViewScale:scale];
175 }
176
177 static BOOL areEssentiallyEqual(double a, double b)
178 {
179     double tolerance = 0.001;
180     return (fabs(a - b) <= tolerance);
181 }
182
183 - (BOOL)validateMenuItem:(NSMenuItem *)menuItem
184 {
185     SEL action = menuItem.action;
186
187     if (action == @selector(zoomIn:))
188         return [self canZoomIn];
189     if (action == @selector(zoomOut:))
190         return [self canZoomOut];
191     if (action == @selector(resetZoom:))
192         return [self canResetZoom];
193     
194     // Disabled until missing WK2 functionality is exposed via API/SPI.
195     if (action == @selector(dumpSourceToConsole:)
196         || action == @selector(forceRepaint:))
197         return NO;
198     
199     if (action == @selector(showHideWebView:))
200         [menuItem setTitle:[_webView isHidden] ? @"Show Web View" : @"Hide Web View"];
201     else if (action == @selector(removeReinsertWebView:))
202         [menuItem setTitle:[_webView window] ? @"Remove Web View" : @"Insert Web View"];
203     else if (action == @selector(toggleZoomMode:))
204         [menuItem setState:_zoomTextOnly ? NSOnState : NSOffState];
205     else if (action == @selector(toggleEditable:))
206         [menuItem setState:self.isEditable ? NSOnState : NSOffState];
207
208     if (action == @selector(setPageScale:))
209         [menuItem setState:areEssentiallyEqual([_webView _pageScale], [self pageScaleForMenuItemTag:[menuItem tag]])];
210
211     if (action == @selector(setViewScale:))
212         [menuItem setState:areEssentiallyEqual([_webView _viewScale], [self viewScaleForMenuItemTag:[menuItem tag]])];
213
214     return YES;
215 }
216
217 - (IBAction)reload:(id)sender
218 {
219     [_webView reload];
220 }
221
222 - (IBAction)forceRepaint:(id)sender
223 {
224     // FIXME: This doesn't actually force a repaint.
225     [_webView setNeedsDisplay:YES];
226 }
227
228 - (IBAction)goBack:(id)sender
229 {
230     [_webView goBack];
231 }
232
233 - (IBAction)goForward:(id)sender
234 {
235     [_webView goForward];
236 }
237
238 - (IBAction)toggleZoomMode:(id)sender
239 {
240     if (_zoomTextOnly) {
241         _zoomTextOnly = NO;
242         double currentTextZoom = _webView._textZoomFactor;
243         _webView._textZoomFactor = 1;
244         _webView._pageZoomFactor = currentTextZoom;
245     } else {
246         _zoomTextOnly = YES;
247         double currentPageZoom = _webView._pageZoomFactor;
248         _webView._textZoomFactor = currentPageZoom;
249         _webView._pageZoomFactor = 1;
250     }
251 }
252
253 - (IBAction)resetZoom:(id)sender
254 {
255     if (![self canResetZoom])
256         return;
257
258     if (_zoomTextOnly)
259         _webView._textZoomFactor = 1;
260     else
261         _webView._pageZoomFactor = 1;
262 }
263
264 - (BOOL)canResetZoom
265 {
266     return _zoomTextOnly ? (_webView._textZoomFactor != 1) : (_webView._pageZoomFactor != 1);
267 }
268
269 - (IBAction)toggleShrinkToFit:(id)sender
270 {
271     _useShrinkToFit = !_useShrinkToFit;
272     toggleUseShrinkToFitButton.image = _useShrinkToFit ? [NSImage imageNamed:@"NSExitFullScreenTemplate"] : [NSImage imageNamed:@"NSEnterFullScreenTemplate"];
273     [_webView _setLayoutMode:_useShrinkToFit ? _WKLayoutModeDynamicSizeComputedFromMinimumDocumentSize : _WKLayoutModeViewSize];
274 }
275
276 - (IBAction)dumpSourceToConsole:(id)sender
277 {
278 }
279
280 - (NSURL *)currentURL
281 {
282     return _webView.URL;
283 }
284
285 - (NSView *)mainContentView
286 {
287     return _webView;
288 }
289
290 - (void)setEditable:(BOOL)editable
291 {
292     [super setEditable:editable];
293     _webView._editable = editable;
294 }
295
296 - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
297 {
298     SEL action = item.action;
299
300     if (action == @selector(goBack:) || action == @selector(goForward:))
301         return [_webView validateUserInterfaceItem:item];
302
303     return YES;
304 }
305
306 - (void)validateToolbar
307 {
308     [toolbar validateVisibleItems];
309 }
310
311 - (BOOL)windowShouldClose:(id)sender
312 {
313     return YES;
314 }
315
316 - (void)windowWillClose:(NSNotification *)notification
317 {
318     [(BrowserAppDelegate *)[[NSApplication sharedApplication] delegate] browserWindowWillClose:self.window];
319     [self autorelease];
320 }
321
322 #define DefaultMinimumZoomFactor (.5)
323 #define DefaultMaximumZoomFactor (3.0)
324 #define DefaultZoomFactorRatio (1.2)
325
326 - (CGFloat)currentZoomFactor
327 {
328     return _zoomTextOnly ? _webView._textZoomFactor : _webView._pageZoomFactor;
329 }
330
331 - (void)setCurrentZoomFactor:(CGFloat)factor
332 {
333     if (_zoomTextOnly)
334         _webView._textZoomFactor = factor;
335     else
336         _webView._pageZoomFactor = factor;
337 }
338
339 - (BOOL)canZoomIn
340 {
341     return self.currentZoomFactor * DefaultZoomFactorRatio < DefaultMaximumZoomFactor;
342 }
343
344 - (void)zoomIn:(id)sender
345 {
346     if (!self.canZoomIn)
347         return;
348
349     self.currentZoomFactor *= DefaultZoomFactorRatio;
350 }
351
352 - (BOOL)canZoomOut
353 {
354     return self.currentZoomFactor / DefaultZoomFactorRatio > DefaultMinimumZoomFactor;
355 }
356
357 - (void)zoomOut:(id)sender
358 {
359     if (!self.canZoomIn)
360         return;
361
362     self.currentZoomFactor /= DefaultZoomFactorRatio;
363 }
364
365 - (void)didChangeSettings
366 {
367     SettingsController *settings = [SettingsController shared];
368     WKPreferences *preferences = _webView.configuration.preferences;
369
370     preferences._tiledScrollingIndicatorVisible = settings.tiledScrollingIndicatorVisible;
371     preferences._compositingBordersVisible = settings.layerBordersVisible;
372     preferences._compositingRepaintCountersVisible = settings.layerBordersVisible;
373     preferences._simpleLineLayoutEnabled = settings.simpleLineLayoutEnabled;
374     preferences._simpleLineLayoutDebugBordersEnabled = settings.simpleLineLayoutDebugBordersEnabled;
375     preferences._acceleratedDrawingEnabled = settings.acceleratedDrawingEnabled;
376     preferences._resourceUsageOverlayVisible = settings.resourceUsageOverlayVisible;
377     preferences._displayListDrawingEnabled = settings.displayListDrawingEnabled;
378     preferences._visualViewportEnabled = settings.visualViewportEnabled;
379     preferences._largeImageAsyncDecodingEnabled = settings.largeImageAsyncDecodingEnabled;
380     preferences._animatedImageAsyncDecodingEnabled = settings.animatedImageAsyncDecodingEnabled;
381
382     _webView.configuration.websiteDataStore._resourceLoadStatisticsEnabled = settings.resourceLoadStatisticsEnabled;
383
384     BOOL useTransparentWindows = settings.useTransparentWindows;
385     if (useTransparentWindows != !_webView._drawsBackground) {
386         [self.window setOpaque:!useTransparentWindows];
387         [self.window setBackgroundColor:[NSColor clearColor]];
388         [self.window setHasShadow:!useTransparentWindows];
389
390         _webView._drawsBackground = !useTransparentWindows;
391
392         [self.window display];
393     }
394
395     BOOL usePaginatedMode = settings.usePaginatedMode;
396     if (usePaginatedMode != (_webView._paginationMode != _WKPaginationModeUnpaginated)) {
397         if (usePaginatedMode) {
398             _webView._paginationMode = _WKPaginationModeLeftToRight;
399             _webView._pageLength = _webView.bounds.size.width / 2;
400             _webView._gapBetweenPages = 10;
401         } else
402             _webView._paginationMode = _WKPaginationModeUnpaginated;
403     }
404     
405     NSUInteger visibleOverlayRegions = 0;
406     if (settings.nonFastScrollableRegionOverlayVisible)
407         visibleOverlayRegions |= _WKNonFastScrollableRegion;
408     if (settings.wheelEventHandlerRegionOverlayVisible)
409         visibleOverlayRegions |= _WKWheelEventHandlerRegion;
410     
411     preferences._visibleDebugOverlayRegions = visibleOverlayRegions;
412
413     [_webView _setHeaderBannerHeight:[settings isSpaceReservedForBanners] ? testHeaderBannerHeight : 0];
414     [_webView _setFooterBannerHeight:[settings isSpaceReservedForBanners] ? testFooterBannerHeight : 0];
415 }
416
417 - (void)updateTitle:(NSString *)title
418 {
419     if (!title) {
420         NSURL *url = _webView.URL;
421         title = url.lastPathComponent ?: url._web_userVisibleString;
422     }
423
424     self.window.title = [NSString stringWithFormat:@"%@%@ [WK2 %d]%@", _isPrivateBrowsingWindow ? @"🙈 " : @"", title, _webView._webProcessIdentifier, _webView._editable ? @" [Editable]" : @""];
425 }
426
427 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
428 {
429     if (context != keyValueObservingContext || object != _webView)
430         return;
431
432     if ([keyPath isEqualToString:@"title"])
433         [self updateTitle:_webView.title];
434     else if ([keyPath isEqualToString:@"URL"])
435         [self updateTextFieldFromURL:_webView.URL];
436 }
437
438 - (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
439 {
440     WK2BrowserWindowController *controller = [[WK2BrowserWindowController alloc] initWithConfiguration:configuration];
441     [controller awakeFromNib];
442     [controller.window makeKeyAndOrderFront:self];
443
444     return controller->_webView;
445 }
446
447 - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler
448 {
449     NSAlert* alert = [[NSAlert alloc] init];
450
451     [alert setMessageText:[NSString stringWithFormat:@"JavaScript alert dialog from %@.", [frame.request.URL absoluteString]]];
452     [alert setInformativeText:message];
453     [alert addButtonWithTitle:@"OK"];
454
455     [alert beginSheetModalForWindow:self.window completionHandler:^void (NSModalResponse response) {
456         completionHandler();
457         [alert release];
458     }];
459 }
460
461 - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler
462 {
463     NSAlert* alert = [[NSAlert alloc] init];
464
465     [alert setMessageText:[NSString stringWithFormat:@"JavaScript confirm dialog from %@.", [frame.request.URL  absoluteString]]];
466     [alert setInformativeText:message];
467     
468     [alert addButtonWithTitle:@"OK"];
469     [alert addButtonWithTitle:@"Cancel"];
470
471     [alert beginSheetModalForWindow:self.window completionHandler:^void (NSModalResponse response) {
472         completionHandler(response == NSAlertFirstButtonReturn);
473         [alert release];
474     }];
475 }
476
477 - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString *result))completionHandler
478 {
479     NSAlert* alert = [[NSAlert alloc] init];
480
481     [alert setMessageText:[NSString stringWithFormat:@"JavaScript prompt dialog from %@.", [frame.request.URL absoluteString]]];
482     [alert setInformativeText:prompt];
483     
484     [alert addButtonWithTitle:@"OK"];
485     [alert addButtonWithTitle:@"Cancel"];
486     
487     NSTextField* input = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 200, 24)];
488     [input setStringValue:defaultText];
489     [alert setAccessoryView:input];
490     
491     [alert beginSheetModalForWindow:self.window completionHandler:^void (NSModalResponse response) {
492         [input validateEditing];
493         completionHandler(response == NSAlertFirstButtonReturn ? [input stringValue] : nil);
494         [alert release];
495     }];
496 }
497
498 #if __has_feature(objc_generics)
499 - (void)webView:(WKWebView *)webView runOpenPanelWithParameters:(WKOpenPanelParameters *)parameters initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSArray<NSURL *> * URLs))completionHandler
500 #else
501 - (void)webView:(WKWebView *)webView runOpenPanelWithParameters:(WKOpenPanelParameters *)parameters initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSArray *URLs))completionHandler
502 #endif
503 {
504     NSOpenPanel *openPanel = [NSOpenPanel openPanel];
505
506     openPanel.allowsMultipleSelection = parameters.allowsMultipleSelection;
507
508     [openPanel beginSheetModalForWindow:webView.window completionHandler:^(NSInteger result) {
509         if (result == NSFileHandlingPanelOKButton)
510             completionHandler(openPanel.URLs);
511         else
512             completionHandler(nil);
513     }];
514 }
515
516 - (void)updateTextFieldFromURL:(NSURL *)URL
517 {
518     if (!URL)
519         return;
520
521     if (!URL.absoluteString.length)
522         return;
523
524     urlText.stringValue = [URL _web_userVisibleString];
525 }
526
527 - (void)loadURLString:(NSString *)urlString
528 {
529     // FIXME: We shouldn't have to set the url text here.
530     [urlText setStringValue:urlString];
531     [self fetch:nil];
532 }
533
534 - (void)loadHTMLString:(NSString *)HTMLString
535 {
536     [_webView loadHTMLString:HTMLString baseURL:nil];
537 }
538
539 static NSSet *dataTypes()
540 {
541     return [WKWebsiteDataStore allWebsiteDataTypes];
542 }
543
544 - (IBAction)fetchWebsiteData:(id)sender
545 {
546     [_configuration.websiteDataStore _fetchDataRecordsOfTypes:dataTypes() withOptions:_WKWebsiteDataStoreFetchOptionComputeSizes completionHandler:^(NSArray *websiteDataRecords) {
547         NSLog(@"did fetch website data %@.", websiteDataRecords);
548     }];
549 }
550
551 - (IBAction)fetchAndClearWebsiteData:(id)sender
552 {
553     [_configuration.websiteDataStore fetchDataRecordsOfTypes:dataTypes() completionHandler:^(NSArray *websiteDataRecords) {
554         [_configuration.websiteDataStore removeDataOfTypes:dataTypes() forDataRecords:websiteDataRecords completionHandler:^{
555             [_configuration.websiteDataStore fetchDataRecordsOfTypes:dataTypes() completionHandler:^(NSArray *websiteDataRecords) {
556                 NSLog(@"did clear website data, after clearing data is %@.", websiteDataRecords);
557             }];
558         }];
559     }];
560 }
561
562 - (IBAction)clearWebsiteData:(id)sender
563 {
564     [_configuration.websiteDataStore removeDataOfTypes:dataTypes() modifiedSince:[NSDate distantPast] completionHandler:^{
565         NSLog(@"Did clear website data.");
566     }];
567 }
568
569 - (IBAction)printWebView:(id)sender
570 {
571     [[_webView _printOperationWithPrintInfo:[NSPrintInfo sharedPrintInfo]] runOperationModalForWindow:self.window delegate:nil didRunSelector:nil contextInfo:nil];
572 }
573
574 #pragma mark WKNavigationDelegate
575
576 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
577 {
578     LOG(@"decidePolicyForNavigationAction");
579
580     if (navigationAction._canHandleRequest) {
581         decisionHandler(WKNavigationActionPolicyAllow);
582         return;
583     }
584
585     if (navigationAction._userInitiatedAction && !navigationAction._userInitiatedAction.isConsumed) {
586         [navigationAction._userInitiatedAction consume];
587         [[NSWorkspace sharedWorkspace] openURL:navigationAction.request.URL];
588     }
589
590     decisionHandler(WKNavigationActionPolicyCancel);
591 }
592
593 - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
594 {
595     LOG(@"decidePolicyForNavigationResponse");
596     decisionHandler(WKNavigationResponsePolicyAllow);
597 }
598
599 - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation
600 {
601     LOG(@"didStartProvisionalNavigation: %@", navigation);
602 }
603
604 - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation
605 {
606     LOG(@"didReceiveServerRedirectForProvisionalNavigation: %@", navigation);
607 }
608
609 - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error
610 {
611     LOG(@"didFailProvisionalNavigation: %@navigation, error: %@", navigation, error);
612 }
613
614 - (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation
615 {
616     LOG(@"didCommitNavigation: %@", navigation);
617     [self updateTitle:nil];
618 }
619
620 - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
621 {
622     LOG(@"didFinishNavigation: %@", navigation);
623     
624     // Banner heights don't persist across page loads (oddly, since Page stores them), so reset on every page load.
625     if ([[SettingsController shared] isSpaceReservedForBanners]) {
626         [_webView _setHeaderBannerHeight:testHeaderBannerHeight];
627         [_webView _setFooterBannerHeight:testFooterBannerHeight];
628     }
629 }
630
631 - (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *__nullable credential))completionHandler
632 {
633     LOG(@"didReceiveAuthenticationChallenge: %@", challenge);
634     completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, nil);
635 }
636
637 - (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error
638 {
639     LOG(@"didFailNavigation: %@, error %@", navigation, error);
640 }
641
642 - (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView
643 {
644     NSLog(@"WebContent process crashed; reloading");
645     [self reload:nil];
646 }
647
648 - (void)_webView:(WKWebView *)webView renderingProgressDidChange:(_WKRenderingProgressEvents)progressEvents
649 {
650     if (progressEvents & _WKRenderingProgressEventFirstLayout)
651         LOG(@"renderingProgressDidChange: %@", @"first layout");
652
653     if (progressEvents & _WKRenderingProgressEventFirstVisuallyNonEmptyLayout)
654         LOG(@"renderingProgressDidChange: %@", @"first visually non-empty layout");
655
656     if (progressEvents & _WKRenderingProgressEventFirstPaintWithSignificantArea)
657         LOG(@"renderingProgressDidChange: %@", @"first paint with significant area");
658
659     if (progressEvents & _WKRenderingProgressEventFirstLayoutAfterSuppressedIncrementalRendering)
660         LOG(@"renderingProgressDidChange: %@", @"first layout after suppressed incremental rendering");
661
662     if (progressEvents & _WKRenderingProgressEventFirstPaintAfterSuppressedIncrementalRendering)
663         LOG(@"renderingProgressDidChange: %@", @"first paint after suppressed incremental rendering");
664 }
665
666 - (void)webView:(WKWebView *)webView shouldLoadIconWithParameters:(_WKLinkIconParameters *)parameters completionHandler:(void (^)(void (^)(NSData*)))completionHandler
667 {
668     completionHandler(^void (NSData *data) {
669         LOG(@"Icon URL %@ received icon data of length %u", parameters.url, (unsigned)data.length);
670     });
671 }
672
673 #pragma mark Find in Page
674
675 - (IBAction)performTextFinderAction:(id)sender
676 {
677     [_textFinder performAction:[sender tag]];
678 }
679
680 - (NSView *)findBarView
681 {
682     return _textFindBarView;
683 }
684
685 - (void)setFindBarView:(NSView *)findBarView
686 {
687     if (_textFindBarView)
688         [_textFindBarView removeFromSuperview];
689     _textFindBarView = findBarView;
690     _findBarVisible = YES;
691     [containerView addSubview:_textFindBarView];
692     [_textFindBarView setFrame:NSMakeRect(0, 0, containerView.bounds.size.width, _textFindBarView.frame.size.height)];
693 }
694
695 - (BOOL)isFindBarVisible
696 {
697     return _findBarVisible;
698 }
699
700 - (void)setFindBarVisible:(BOOL)findBarVisible
701 {
702     _findBarVisible = findBarVisible;
703     if (findBarVisible)
704         [containerView addSubview:_textFindBarView];
705     else
706         [_textFindBarView removeFromSuperview];
707 }
708
709 - (NSView *)contentView
710 {
711     return _webView;
712 }
713
714 - (void)findBarViewDidChangeHeight
715 {
716 }
717
718 @end
719
720 #endif // WK_API_ENABLED