Stop unnecessarily copying WKWebViewConfiguration in a few places
[WebKit-https.git] / Source / WebKit2 / UIProcess / API / Cocoa / WKWebView.mm
1 /*
2  * Copyright (C) 2014, 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 "WKWebViewInternal.h"
28
29 #if WK_API_ENABLED
30
31 #import "APIFormClient.h"
32 #import "APIPageConfiguration.h"
33 #import "APISerializedScriptValue.h"
34 #import "CompletionHandlerCallChecker.h"
35 #import "DiagnosticLoggingClient.h"
36 #import "FindClient.h"
37 #import "LegacySessionStateCoding.h"
38 #import "NavigationState.h"
39 #import "ObjCObjectGraph.h"
40 #import "RemoteLayerTreeScrollingPerformanceData.h"
41 #import "RemoteLayerTreeTransaction.h"
42 #import "RemoteObjectRegistry.h"
43 #import "RemoteObjectRegistryMessages.h"
44 #import "UIDelegate.h"
45 #import "ViewGestureController.h"
46 #import "ViewSnapshotStore.h"
47 #import "WKBackForwardListInternal.h"
48 #import "WKBackForwardListItemInternal.h"
49 #import "WKBrowsingContextHandleInternal.h"
50 #import "WKErrorInternal.h"
51 #import "WKHistoryDelegatePrivate.h"
52 #import "WKLayoutMode.h"
53 #import "WKNSData.h"
54 #import "WKNSURLExtras.h"
55 #import "WKNavigationDelegate.h"
56 #import "WKNavigationInternal.h"
57 #import "WKPreferencesInternal.h"
58 #import "WKProcessPoolInternal.h"
59 #import "WKSharedAPICast.h"
60 #import "WKUIDelegate.h"
61 #import "WKUIDelegatePrivate.h"
62 #import "WKUserContentControllerInternal.h"
63 #import "WKWebViewConfigurationInternal.h"
64 #import "WKWebViewContentProvider.h"
65 #import "WKWebsiteDataStoreInternal.h"
66 #import "WebBackForwardList.h"
67 #import "WebCertificateInfo.h"
68 #import "WebFormSubmissionListenerProxy.h"
69 #import "WebKitSystemInterface.h"
70 #import "WebPageGroup.h"
71 #import "WebPageProxy.h"
72 #import "WebPreferencesKeys.h"
73 #import "WebProcessPool.h"
74 #import "WebProcessProxy.h"
75 #import "WebViewImpl.h"
76 #import "_WKDiagnosticLoggingDelegate.h"
77 #import "_WKFindDelegate.h"
78 #import "_WKFormDelegate.h"
79 #import "_WKFrameHandleInternal.h"
80 #import "_WKHitTestResultInternal.h"
81 #import "_WKInputDelegate.h"
82 #import "_WKRemoteObjectRegistryInternal.h"
83 #import "_WKSessionStateInternal.h"
84 #import "_WKVisitedLinkStoreInternal.h"
85 #import <WebCore/IOSurface.h>
86 #import <WebCore/JSDOMBinding.h>
87 #import <WebCore/NSTextFinderSPI.h>
88 #import <wtf/HashMap.h>
89 #import <wtf/MathExtras.h>
90 #import <wtf/NeverDestroyed.h>
91 #import <wtf/Optional.h>
92 #import <wtf/RetainPtr.h>
93 #import <wtf/TemporaryChange.h>
94
95 #if PLATFORM(IOS)
96 #import "_WKWebViewPrintFormatter.h"
97 #import "PrintInfo.h"
98 #import "ProcessThrottler.h"
99 #import "RemoteLayerTreeDrawingAreaProxy.h"
100 #import "RemoteScrollingCoordinatorProxy.h"
101 #import "UIKitSPI.h"
102 #import "WKContentViewInteraction.h"
103 #import "WKPDFView.h"
104 #import "WKScrollView.h"
105 #import "WKWebViewContentProviderRegistry.h"
106 #import "WebPageMessages.h"
107 #import "WebVideoFullscreenManagerProxy.h"
108 #import <UIKit/UIApplication.h>
109 #import <WebCore/CoreGraphicsSPI.h>
110 #import <WebCore/DynamicLinkerSPI.h>
111 #import <WebCore/FrameLoaderTypes.h>
112 #import <WebCore/InspectorOverlay.h>
113 #import <WebCore/QuartzCoreSPI.h>
114
115 @interface UIScrollView (UIScrollViewInternal)
116 - (void)_adjustForAutomaticKeyboardInfo:(NSDictionary*)info animated:(BOOL)animated lastAdjustment:(CGFloat*)lastAdjustment;
117 - (BOOL)_isScrollingToTop;
118 - (BOOL)_isInterruptingDeceleration;
119 - (CGPoint)_animatedTargetOffset;
120 @end
121
122 @interface UIPeripheralHost(UIKitInternal)
123 - (CGFloat)getVerticalOverlapForView:(UIView *)view usingKeyboardInfo:(NSDictionary *)info;
124 @end
125
126 @interface UIView (UIViewInternal)
127 - (UIViewController *)_viewControllerForAncestor;
128 @end
129
130 @interface UIWindow (UIWindowInternal)
131 - (BOOL)_isHostedInAnotherProcess;
132 @end
133
134 @interface UIViewController (UIViewControllerInternal)
135 - (UIViewController *)_rootAncestorViewController;
136 - (UIViewController *)_viewControllerForSupportedInterfaceOrientations;
137 @end
138
139 enum class DynamicViewportUpdateMode {
140     NotResizing,
141     ResizingWithAnimation,
142     ResizingWithDocumentHidden,
143 };
144
145 #endif
146
147 #if PLATFORM(MAC)
148 #import "WKTextFinderClient.h"
149 #import "WKViewInternal.h"
150 #import <WebCore/ColorMac.h>
151
152 @interface WKWebView () <WebViewImplDelegate>
153 @end
154 #endif
155
156 static HashMap<WebKit::WebPageProxy*, WKWebView *>& pageToViewMap()
157 {
158     static NeverDestroyed<HashMap<WebKit::WebPageProxy*, WKWebView *>> map;
159     return map;
160 }
161
162 WKWebView* fromWebPageProxy(WebKit::WebPageProxy& page)
163 {
164     return pageToViewMap().get(&page);
165 }
166
167 @implementation WKWebView {
168     std::unique_ptr<WebKit::NavigationState> _navigationState;
169     std::unique_ptr<WebKit::UIDelegate> _uiDelegate;
170
171     _WKRenderingProgressEvents _observedRenderingProgressEvents;
172
173     WebKit::WeakObjCPtr<id <_WKInputDelegate>> _inputDelegate;
174
175 #if PLATFORM(IOS)
176     RetainPtr<_WKRemoteObjectRegistry> _remoteObjectRegistry;
177
178     RetainPtr<WKScrollView> _scrollView;
179     RetainPtr<WKContentView> _contentView;
180
181     BOOL _overridesMinimumLayoutSize;
182     CGSize _minimumLayoutSizeOverride;
183     BOOL _overridesMaximumUnobscuredSize;
184     CGSize _maximumUnobscuredSizeOverride;
185     CGRect _inputViewBounds;
186     CGFloat _viewportMetaTagWidth;
187     CGFloat _initialScaleFactor;
188     BOOL _fastClickingIsDisabled;
189
190     BOOL _allowsLinkPreview;
191
192     UIEdgeInsets _obscuredInsets;
193     BOOL _haveSetObscuredInsets;
194     BOOL _isChangingObscuredInsetsInteractively;
195
196     UIInterfaceOrientation _interfaceOrientationOverride;
197     BOOL _overridesInterfaceOrientation;
198
199     BOOL _hasCommittedLoadForMainFrame;
200     BOOL _needsResetViewStateAfterCommitLoadForMainFrame;
201     uint64_t _firstPaintAfterCommitLoadTransactionID;
202     DynamicViewportUpdateMode _dynamicViewportUpdateMode;
203     CATransform3D _resizeAnimationTransformAdjustments;
204     uint64_t _resizeAnimationTransformTransactionID;
205     RetainPtr<UIView> _resizeAnimationView;
206     CGFloat _lastAdjustmentForScroller;
207     Optional<CGRect> _frozenVisibleContentRect;
208     Optional<CGRect> _frozenUnobscuredContentRect;
209
210     BOOL _needsToRestoreExposedRect;
211     WebCore::FloatRect _exposedRectToRestore;
212     BOOL _needsToRestoreUnobscuredCenter;
213     WebCore::FloatPoint _unobscuredCenterToRestore;
214     uint64_t _firstTransactionIDAfterPageRestore;
215     double _scaleToRestore;
216
217     std::unique_ptr<WebKit::ViewGestureController> _gestureController;
218     BOOL _allowsBackForwardNavigationGestures;
219
220     RetainPtr<UIView <WKWebViewContentProvider>> _customContentView;
221     RetainPtr<UIView> _customContentFixedOverlayView;
222
223     WebCore::Color _scrollViewBackgroundColor;
224
225     // This value tracks the current adjustment added to the bottom inset due to the keyboard sliding out from the bottom
226     // when computing obscured content insets. This is used when updating the visible content rects where we should not
227     // include this adjustment.
228     CGFloat _totalScrollViewBottomInsetAdjustmentForKeyboard;
229     BOOL _currentlyAdjustingScrollViewInsetsForKeyboard;
230
231     BOOL _delayUpdateVisibleContentRects;
232     BOOL _hadDelayedUpdateVisibleContentRects;
233
234     BOOL _pageIsPrintingToPDF;
235     RetainPtr<CGPDFDocumentRef> _printedDocument;
236     Vector<std::function<void ()>> _snapshotsDeferredDuringResize;
237 #endif
238 #if PLATFORM(MAC)
239     std::unique_ptr<WebKit::WebViewImpl> _impl;
240     RetainPtr<WKTextFinderClient> _textFinderClient;
241 #endif
242 }
243
244 - (instancetype)initWithFrame:(CGRect)frame
245 {
246     return [self initWithFrame:frame configuration:adoptNS([[WKWebViewConfiguration alloc] init]).get()];
247 }
248
249 #if PLATFORM(IOS)
250 static int32_t deviceOrientationForUIInterfaceOrientation(UIInterfaceOrientation orientation)
251 {
252     switch (orientation) {
253     case UIInterfaceOrientationUnknown:
254     case UIInterfaceOrientationPortrait:
255         return 0;
256     case UIInterfaceOrientationPortraitUpsideDown:
257         return 180;
258     case UIInterfaceOrientationLandscapeLeft:
259         return -90;
260     case UIInterfaceOrientationLandscapeRight:
261         return 90;
262     }
263 }
264
265 static int32_t deviceOrientation()
266 {
267     return deviceOrientationForUIInterfaceOrientation([[UIApplication sharedApplication] statusBarOrientation]);
268 }
269
270 - (BOOL)_isShowingVideoPictureInPicture
271 {
272     if (!_page || !_page->videoFullscreenManager())
273         return false;
274     
275     return _page->videoFullscreenManager()->hasMode(WebCore::HTMLMediaElementEnums::VideoFullscreenModePictureInPicture);
276 }
277
278 - (BOOL)_mayAutomaticallyShowVideoPictureInPicture
279 {
280 #if !HAVE(AVKIT)
281     return false;
282 #else
283     if (!_page || !_page->videoFullscreenManager())
284         return false;
285
286     return _page->videoFullscreenManager()->mayAutomaticallyShowVideoPictureInPicture();
287 #endif
288 }
289
290 static bool shouldAllowPictureInPictureMediaPlayback()
291 {
292     static bool shouldAllowPictureInPictureMediaPlayback = dyld_get_program_sdk_version() >= DYLD_IOS_VERSION_9_0;
293     return shouldAllowPictureInPictureMediaPlayback;
294 }
295
296 #endif
297
298 - (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration
299 {
300     if (!(self = [super initWithFrame:frame]))
301         return nil;
302
303     if (!configuration)
304         [NSException raise:NSInvalidArgumentException format:@"Configuration cannot be nil"];
305
306     _configuration = adoptNS([configuration copy]);
307
308     if (WKWebView *relatedWebView = [_configuration _relatedWebView]) {
309         WKProcessPool *processPool = [_configuration processPool];
310         WKProcessPool *relatedWebViewProcessPool = [relatedWebView->_configuration processPool];
311         if (processPool && processPool != relatedWebViewProcessPool)
312             [NSException raise:NSInvalidArgumentException format:@"Related web view %@ has process pool %@ but configuration specifies a different process pool %@", relatedWebView, relatedWebViewProcessPool, configuration.processPool];
313
314         [_configuration setProcessPool:relatedWebViewProcessPool];
315     }
316
317     [_configuration _validate];
318
319
320     WebKit::WebProcessPool& processPool = *[_configuration processPool]->_processPool;
321     
322     auto pageConfiguration = API::PageConfiguration::create();
323
324     pageConfiguration->setProcessPool(&processPool);
325     pageConfiguration->setPreferences([_configuration preferences]->_preferences.get());
326     if (WKWebView *relatedWebView = [_configuration _relatedWebView])
327         pageConfiguration->setRelatedPage(relatedWebView->_page.get());
328
329     pageConfiguration->setUserContentController([_configuration userContentController]->_userContentControllerProxy.get());
330     pageConfiguration->setVisitedLinkStore([_configuration _visitedLinkStore]->_visitedLinkStore.get());
331     pageConfiguration->setWebsiteDataStore([_configuration websiteDataStore]->_websiteDataStore.get());
332     pageConfiguration->setTreatsSHA1SignedCertificatesAsInsecure([_configuration _treatsSHA1SignedCertificatesAsInsecure]);
333
334     RefPtr<WebKit::WebPageGroup> pageGroup;
335     NSString *groupIdentifier = configuration._groupIdentifier;
336     if (groupIdentifier.length) {
337         pageGroup = WebKit::WebPageGroup::create(configuration._groupIdentifier);
338         pageConfiguration->setPageGroup(pageGroup.get());
339     }
340
341     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::suppressesIncrementalRenderingKey(), WebKit::WebPreferencesStore::Value(!![_configuration suppressesIncrementalRendering]));
342
343     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::shouldRespectImageOrientationKey(), WebKit::WebPreferencesStore::Value(!![_configuration _respectsImageOrientation]));
344     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::shouldPrintBackgroundsKey(), WebKit::WebPreferencesStore::Value(!![_configuration _printsBackgrounds]));
345     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::incrementalRenderingSuppressionTimeoutKey(), WebKit::WebPreferencesStore::Value([_configuration _incrementalRenderingSuppressionTimeout]));
346     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::javaScriptMarkupEnabledKey(), WebKit::WebPreferencesStore::Value(!![_configuration _allowsJavaScriptMarkup]));
347     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::shouldConvertPositionStyleOnCopyKey(), WebKit::WebPreferencesStore::Value(!![_configuration _convertsPositionStyleOnCopy]));
348     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::httpEquivEnabledKey(), WebKit::WebPreferencesStore::Value(!![_configuration _allowsMetaRefresh]));
349
350 #if PLATFORM(MAC)
351     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::showsURLsInToolTipsEnabledKey(), WebKit::WebPreferencesStore::Value(!![_configuration _showsURLsInToolTips]));
352     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::serviceControlsEnabledKey(), WebKit::WebPreferencesStore::Value(!![_configuration _serviceControlsEnabled]));
353     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::imageControlsEnabledKey(), WebKit::WebPreferencesStore::Value(!![_configuration _imageControlsEnabled]));
354 #endif
355
356 #if PLATFORM(IOS)
357     pageConfiguration->setAlwaysRunsAtForegroundPriority([_configuration _alwaysRunsAtForegroundPriority]);
358
359     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::allowsInlineMediaPlaybackKey(), WebKit::WebPreferencesStore::Value(!![_configuration allowsInlineMediaPlayback]));
360     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::inlineMediaPlaybackRequiresPlaysInlineAttributeKey(), WebKit::WebPreferencesStore::Value(!![_configuration _inlineMediaPlaybackRequiresPlaysInlineAttribute]));
361     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::allowsPictureInPictureMediaPlaybackKey(), WebKit::WebPreferencesStore::Value(!![_configuration allowsPictureInPictureMediaPlayback] && shouldAllowPictureInPictureMediaPlayback()));
362     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::requiresUserGestureForMediaPlaybackKey(), WebKit::WebPreferencesStore::Value(!![_configuration requiresUserActionForMediaPlayback]));
363     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::requiresUserGestureForAudioPlaybackKey(), WebKit::WebPreferencesStore::Value(!![_configuration _requiresUserActionForAudioPlayback]));
364     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::mediaDataLoadsAutomaticallyKey(), WebKit::WebPreferencesStore::Value(!![_configuration _mediaDataLoadsAutomatically]));
365 #endif
366 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
367     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::allowsAirPlayForMediaPlaybackKey(), WebKit::WebPreferencesStore::Value(!![_configuration allowsAirPlayForMediaPlayback]));
368 #endif
369
370 #if PLATFORM(IOS)
371     CGRect bounds = self.bounds;
372     _scrollView = adoptNS([[WKScrollView alloc] initWithFrame:bounds]);
373     [_scrollView setInternalDelegate:self];
374     [_scrollView setBouncesZoom:YES];
375
376     [self addSubview:_scrollView.get()];
377
378     _contentView = adoptNS([[WKContentView alloc] initWithFrame:bounds processPool:processPool configuration:WTF::move(pageConfiguration) webView:self]);
379
380     _page = [_contentView page];
381     _page->setDeviceOrientation(deviceOrientation());
382
383     [_contentView layer].anchorPoint = CGPointZero;
384     [_contentView setFrame:bounds];
385     [_scrollView addSubview:_contentView.get()];
386     [_scrollView addSubview:[_contentView unscaledView]];
387     [self _updateScrollViewBackground];
388
389     _viewportMetaTagWidth = WebCore::ViewportArguments::ValueAuto;
390     _initialScaleFactor = 1;
391     _fastClickingIsDisabled = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebKitFastClickingDisabled"];
392
393     [self _frameOrBoundsChanged];
394
395     NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
396     [center addObserver:self selector:@selector(_keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];
397     [center addObserver:self selector:@selector(_keyboardDidChangeFrame:) name:UIKeyboardDidChangeFrameNotification object:nil];
398     [center addObserver:self selector:@selector(_keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
399     [center addObserver:self selector:@selector(_keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
400     [center addObserver:self selector:@selector(_windowDidRotate:) name:UIWindowDidRotateNotification object:nil];
401     [center addObserver:self selector:@selector(_contentSizeCategoryDidChange:) name:UIContentSizeCategoryDidChangeNotification object:nil];
402     _page->contentSizeCategoryDidChange([self _contentSizeCategory]);
403
404     [[_configuration _contentProviderRegistry] addPage:*_page];
405 #endif
406
407 #if PLATFORM(MAC)
408     _impl = std::make_unique<WebKit::WebViewImpl>(self, self, processPool, WTF::move(pageConfiguration));
409     _page = &_impl->page();
410
411 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
412     _impl->setAutomaticallyAdjustsContentInsets(true);
413 #endif
414 #endif
415
416     _page->setBackgroundExtendsBeyondPage(true);
417
418     if (NSString *applicationNameForUserAgent = configuration.applicationNameForUserAgent)
419         _page->setApplicationNameForUserAgent(applicationNameForUserAgent);
420
421     _navigationState = std::make_unique<WebKit::NavigationState>(self);
422     _uiDelegate = std::make_unique<WebKit::UIDelegate>(self);
423     _page->setFindClient(std::make_unique<WebKit::FindClient>(self));
424     _page->setDiagnosticLoggingClient(std::make_unique<WebKit::DiagnosticLoggingClient>(self));
425
426     pageToViewMap().add(_page.get(), self);
427
428     return self;
429 }
430
431 - (instancetype)initWithCoder:(NSCoder *)coder
432 {
433     [self release];
434     return nil;
435 }
436
437 - (void)dealloc
438 {
439 #if PLATFORM(MAC)
440     [_textFinderClient willDestroyView:self];
441 #endif
442
443 #if PLATFORM(IOS)
444     if (_remoteObjectRegistry)
445         _page->process().processPool().removeMessageReceiver(Messages::RemoteObjectRegistry::messageReceiverName(), _page->pageID());
446
447     _page->close();
448
449     [_remoteObjectRegistry _invalidate];
450     [[_configuration _contentProviderRegistry] removePage:*_page];
451     [[NSNotificationCenter defaultCenter] removeObserver:self];
452     [_scrollView setInternalDelegate:nil];
453 #endif
454
455     pageToViewMap().remove(_page.get());
456
457     [super dealloc];
458 }
459
460 - (WKWebViewConfiguration *)configuration
461 {
462     return [[_configuration copy] autorelease];
463 }
464
465 - (WKBackForwardList *)backForwardList
466 {
467     return wrapper(_page->backForwardList());
468 }
469
470 - (id <WKNavigationDelegate>)navigationDelegate
471 {
472     return _navigationState->navigationDelegate().autorelease();
473 }
474
475 - (void)setNavigationDelegate:(id <WKNavigationDelegate>)navigationDelegate
476 {
477     _page->setNavigationClient(_navigationState->createNavigationClient());
478     _navigationState->setNavigationDelegate(navigationDelegate);
479 }
480
481 - (id <WKUIDelegate>)UIDelegate
482 {
483     return _uiDelegate->delegate().autorelease();
484 }
485
486 - (void)setUIDelegate:(id<WKUIDelegate>)UIDelegate
487 {
488 #if ENABLE(CONTEXT_MENUS)
489     _page->setContextMenuClient(_uiDelegate->createContextMenuClient());
490 #endif
491     _page->setUIClient(_uiDelegate->createUIClient());
492     _uiDelegate->setDelegate(UIDelegate);
493 }
494
495 - (WKNavigation *)loadRequest:(NSURLRequest *)request
496 {
497     auto navigation = _page->loadRequest(request);
498     if (!navigation)
499         return nil;
500
501     return [wrapper(*navigation.release().leakRef()) autorelease];
502 }
503
504 - (WKNavigation *)loadFileURL:(NSURL *)URL allowingReadAccessToURL:(NSURL *)readAccessURL
505 {
506     if (![URL isFileURL])
507         [NSException raise:NSInvalidArgumentException format:@"%@ is not a file URL", URL];
508
509     if (![readAccessURL isFileURL])
510         [NSException raise:NSInvalidArgumentException format:@"%@ is not a file URL", readAccessURL];
511
512     auto navigation = _page->loadFile([URL _web_originalDataAsWTFString], [readAccessURL _web_originalDataAsWTFString]);
513     if (!navigation)
514         return nil;
515
516     return [wrapper(*navigation.release().leakRef()) autorelease];
517 }
518
519 - (WKNavigation *)loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL
520 {
521     NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
522
523     return [self loadData:data MIMEType:@"text/html" characterEncodingName:@"UTF-8" baseURL:baseURL];
524 }
525
526 - (WKNavigation *)loadData:(NSData *)data MIMEType:(NSString *)MIMEType characterEncodingName:(NSString *)characterEncodingName baseURL:(NSURL *)baseURL
527 {
528     auto navigation = _page->loadData(API::Data::createWithoutCopying(data).ptr(), MIMEType, characterEncodingName, baseURL.absoluteString);
529     if (!navigation)
530         return nil;
531
532     return [wrapper(*navigation.release().leakRef()) autorelease];
533 }
534
535 - (WKNavigation *)goToBackForwardListItem:(WKBackForwardListItem *)item
536 {
537     auto navigation = _page->goToBackForwardItem(&item._item);
538     if (!navigation)
539         return nil;
540
541     return [wrapper(*navigation.release().leakRef()) autorelease];
542 }
543
544 - (NSString *)title
545 {
546     return _page->pageLoadState().title();
547 }
548
549 - (NSURL *)URL
550 {
551     return [NSURL _web_URLWithWTFString:_page->pageLoadState().activeURL()];
552 }
553
554 - (BOOL)isLoading
555 {
556     return _page->pageLoadState().isLoading();
557 }
558
559 - (double)estimatedProgress
560 {
561     return _page->pageLoadState().estimatedProgress();
562 }
563
564 - (BOOL)hasOnlySecureContent
565 {
566     return _page->pageLoadState().hasOnlySecureContent();
567 }
568
569 - (NSArray *)certificateChain
570 {
571     auto certificateInfo = _page->pageLoadState().certificateInfo();
572     if (!certificateInfo)
573         return @[ ];
574
575     return (NSArray *)certificateInfo->certificateInfo().certificateChain() ?: @[ ];
576 }
577
578 - (BOOL)canGoBack
579 {
580     return _page->pageLoadState().canGoBack();
581 }
582
583 - (BOOL)canGoForward
584 {
585     return _page->pageLoadState().canGoForward();
586 }
587
588 - (WKNavigation *)goBack
589 {
590     auto navigation = _page->goBack();
591     if (!navigation)
592         return nil;
593  
594     return [wrapper(*navigation.release().leakRef()) autorelease];
595 }
596
597 - (WKNavigation *)goForward
598 {
599     auto navigation = _page->goForward();
600     if (!navigation)
601         return nil;
602
603     return [wrapper(*navigation.release().leakRef()) autorelease];
604 }
605
606 - (WKNavigation *)reload
607 {
608     const bool reloadFromOrigin = false;
609     const bool contentBlockersEnabled = true;
610     auto navigation = _page->reload(reloadFromOrigin, contentBlockersEnabled);
611     if (!navigation)
612         return nil;
613
614     return [wrapper(*navigation.release().leakRef()) autorelease];
615 }
616
617 - (WKNavigation *)reloadFromOrigin
618 {
619     const bool reloadFromOrigin = true;
620     const bool contentBlockersEnabled = true;
621     auto navigation = _page->reload(reloadFromOrigin, contentBlockersEnabled);
622     if (!navigation)
623         return nil;
624
625     return [wrapper(*navigation.release().leakRef()) autorelease];
626 }
627
628 - (void)stopLoading
629 {
630     _page->stopLoading();
631 }
632
633 static WKErrorCode callbackErrorCode(WebKit::CallbackBase::Error error)
634 {
635     switch (error) {
636     case WebKit::CallbackBase::Error::None:
637         ASSERT_NOT_REACHED();
638         return WKErrorUnknown;
639
640     case WebKit::CallbackBase::Error::Unknown:
641         return WKErrorUnknown;
642
643     case WebKit::CallbackBase::Error::ProcessExited:
644         return WKErrorWebContentProcessTerminated;
645
646     case WebKit::CallbackBase::Error::OwnerWasInvalidated:
647         return WKErrorWebViewInvalidated;
648     }
649 }
650
651 - (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^)(id, NSError *))completionHandler
652 {
653     auto handler = adoptNS([completionHandler copy]);
654
655     _page->runJavaScriptInMainFrame(javaScriptString, [handler](API::SerializedScriptValue* serializedScriptValue, bool hadException, const WebCore::ExceptionDetails& details, WebKit::ScriptValueCallback::Error errorCode) {
656         if (!handler)
657             return;
658
659         if (errorCode != WebKit::ScriptValueCallback::Error::None) {
660             auto error = createNSError(callbackErrorCode(errorCode));
661             if (errorCode == WebKit::ScriptValueCallback::Error::OwnerWasInvalidated) {
662                 // The OwnerWasInvalidated callback is synchronous. We don't want to call the block from within it
663                 // because that can trigger re-entrancy bugs in WebKit.
664                 // FIXME: It would be even better if GenericCallback did this for us.
665                 dispatch_async(dispatch_get_main_queue(), [handler, error] {
666                     auto rawHandler = (void (^)(id, NSError *))handler.get();
667                     rawHandler(nil, error.get());
668                 });
669                 return;
670             }
671
672             auto rawHandler = (void (^)(id, NSError *))handler.get();
673             rawHandler(nil, error.get());
674             return;
675         }
676
677         auto rawHandler = (void (^)(id, NSError *))handler.get();
678         if (hadException) {
679             ASSERT(!serializedScriptValue);
680
681             RetainPtr<NSMutableDictionary> userInfo = adoptNS([[NSMutableDictionary alloc] init]);
682
683             [userInfo setObject:localizedDescriptionForErrorCode(WKErrorJavaScriptExceptionOccurred) forKey:NSLocalizedDescriptionKey];
684             [userInfo setObject:static_cast<NSString *>(details.message) forKey:_WKJavaScriptExceptionMessageErrorKey];
685             [userInfo setObject:@(details.lineNumber) forKey:_WKJavaScriptExceptionLineNumberErrorKey];
686             [userInfo setObject:@(details.columnNumber) forKey:_WKJavaScriptExceptionColumnNumberErrorKey];
687
688             if (!details.sourceURL.isEmpty())
689                 [userInfo setObject:[NSURL _web_URLWithWTFString:details.sourceURL] forKey:_WKJavaScriptExceptionSourceURLErrorKey];
690
691             rawHandler(nil, adoptNS([[NSError alloc] initWithDomain:WKErrorDomain code:WKErrorJavaScriptExceptionOccurred userInfo:userInfo.get()]).get());
692             return;
693         }
694
695         if (!serializedScriptValue) {
696             rawHandler(nil, createNSError(WKErrorJavaScriptResultTypeIsUnsupported).get());
697             return;
698         }
699
700         id body = API::SerializedScriptValue::deserialize(*serializedScriptValue->internalRepresentation(), 0);
701         rawHandler(body, nil);
702     });
703 }
704
705 - (NSString *)customUserAgent
706 {
707     return _page->customUserAgent();
708 }
709
710 - (void)setCustomUserAgent:(NSString *)customUserAgent
711 {
712     _page->setCustomUserAgent(customUserAgent);
713 }
714
715 - (WKPageRef)_pageForTesting
716 {
717     return toAPI(_page.get());
718 }
719
720 - (BOOL)allowsLinkPreview
721 {
722 #if PLATFORM(MAC)
723     return _impl->allowsLinkPreview();
724 #elif PLATFORM(IOS)
725     return _allowsLinkPreview;
726 #endif
727 }
728
729 - (void)setAllowsLinkPreview:(BOOL)allowsLinkPreview
730 {
731 #if PLATFORM(MAC)
732     _impl->setAllowsLinkPreview(allowsLinkPreview);
733     return;
734 #elif PLATFORM(IOS)
735     if (_allowsLinkPreview == allowsLinkPreview)
736         return;
737
738     _allowsLinkPreview = allowsLinkPreview;
739
740 #if HAVE(LINK_PREVIEW)
741     if (_allowsLinkPreview)
742         [_contentView _registerPreview];
743     else
744         [_contentView _unregisterPreview];
745 #endif // HAVE(LINK_PREVIEW)
746 #endif // PLATFORM(IOS)
747 }
748
749 #pragma mark iOS-specific methods
750
751 #if PLATFORM(IOS)
752 - (void)setFrame:(CGRect)frame
753 {
754     CGRect oldFrame = self.frame;
755     [super setFrame:frame];
756
757     if (!CGSizeEqualToSize(oldFrame.size, frame.size))
758         [self _frameOrBoundsChanged];
759 }
760
761 - (void)setBounds:(CGRect)bounds
762 {
763     CGRect oldBounds = self.bounds;
764     [super setBounds:bounds];
765     [_customContentFixedOverlayView setFrame:self.bounds];
766
767     if (!CGSizeEqualToSize(oldBounds.size, bounds.size))
768         [self _frameOrBoundsChanged];
769 }
770
771 - (UIScrollView *)scrollView
772 {
773     return _scrollView.get();
774 }
775
776 - (WKBrowsingContextController *)browsingContextController
777 {
778     return [_contentView browsingContextController];
779 }
780
781 - (BOOL)becomeFirstResponder
782 {
783     return [_contentView becomeFirstResponder] || [super becomeFirstResponder];
784 }
785
786 static inline CGFloat floorToDevicePixel(CGFloat input, float deviceScaleFactor)
787 {
788     return CGFloor(input * deviceScaleFactor) / deviceScaleFactor;
789 }
790
791 static inline bool pointsEqualInDevicePixels(CGPoint a, CGPoint b, float deviceScaleFactor)
792 {
793     return fabs(a.x * deviceScaleFactor - b.x * deviceScaleFactor) < std::numeric_limits<float>::epsilon()
794         && fabs(a.y * deviceScaleFactor - b.y * deviceScaleFactor) < std::numeric_limits<float>::epsilon();
795 }
796
797 static CGSize roundScrollViewContentSize(const WebKit::WebPageProxy& page, CGSize contentSize)
798 {
799     float deviceScaleFactor = page.deviceScaleFactor();
800     return CGSizeMake(floorToDevicePixel(contentSize.width, deviceScaleFactor), floorToDevicePixel(contentSize.height, deviceScaleFactor));
801 }
802
803 - (UIView *)_currentContentView
804 {
805     return _customContentView ? _customContentView.get() : _contentView.get();
806 }
807
808 - (WKWebViewContentProviderRegistry *)_contentProviderRegistry
809 {
810     return [_configuration _contentProviderRegistry];
811 }
812
813 - (WKSelectionGranularity)_selectionGranularity
814 {
815     return [_configuration selectionGranularity];
816 }
817
818 - (void)_setHasCustomContentView:(BOOL)pageHasCustomContentView loadedMIMEType:(const WTF::String&)mimeType
819 {
820     if (pageHasCustomContentView) {
821         [_customContentView removeFromSuperview];
822         [_customContentFixedOverlayView removeFromSuperview];
823
824         Class representationClass = [[_configuration _contentProviderRegistry] providerForMIMEType:mimeType];
825         ASSERT(representationClass);
826         _customContentView = adoptNS([[representationClass alloc] web_initWithFrame:self.bounds webView:self]);
827         _customContentFixedOverlayView = adoptNS([[UIView alloc] initWithFrame:self.bounds]);
828         [_customContentFixedOverlayView setUserInteractionEnabled:NO];
829
830         [[_contentView unscaledView] removeFromSuperview];
831         [_contentView removeFromSuperview];
832         [_scrollView addSubview:_customContentView.get()];
833         [self addSubview:_customContentFixedOverlayView.get()];
834
835         [_customContentView web_setMinimumSize:self.bounds.size];
836         [_customContentView web_setFixedOverlayView:_customContentFixedOverlayView.get()];
837     } else if (_customContentView) {
838         [_customContentView removeFromSuperview];
839         _customContentView = nullptr;
840
841         [_customContentFixedOverlayView removeFromSuperview];
842         _customContentFixedOverlayView = nullptr;
843
844         [_scrollView addSubview:_contentView.get()];
845         [_scrollView addSubview:[_contentView unscaledView]];
846         [_scrollView setContentSize:roundScrollViewContentSize(*_page, [_contentView frame].size)];
847
848         [_customContentFixedOverlayView setFrame:self.bounds];
849         [self addSubview:_customContentFixedOverlayView.get()];
850     }
851 }
852
853 - (void)_didFinishLoadingDataForCustomContentProviderWithSuggestedFilename:(const String&)suggestedFilename data:(NSData *)data
854 {
855     ASSERT(_customContentView);
856     [_customContentView web_setContentProviderData:data suggestedFilename:suggestedFilename];
857
858     // FIXME: It may make more sense for custom content providers to invoke this when they're ready,
859     // because there's no guarantee that all custom content providers will lay out synchronously.
860     _page->didLayoutForCustomContentProvider();
861 }
862
863 - (void)_willInvokeUIScrollViewDelegateCallback
864 {
865     _delayUpdateVisibleContentRects = YES;
866 }
867
868 - (void)_didInvokeUIScrollViewDelegateCallback
869 {
870     _delayUpdateVisibleContentRects = NO;
871     if (_hadDelayedUpdateVisibleContentRects) {
872         _hadDelayedUpdateVisibleContentRects = NO;
873         [self _updateVisibleContentRects];
874     }
875 }
876
877 static CGFloat contentZoomScale(WKWebView *webView)
878 {
879     CGFloat scale = webView._currentContentView.layer.affineTransform.a;
880     ASSERT(scale == [webView->_scrollView zoomScale]);
881     return scale;
882 }
883
884 static WebCore::Color baseScrollViewBackgroundColor(WKWebView *webView)
885 {
886     if (webView->_customContentView)
887         return [webView->_customContentView backgroundColor].CGColor;
888
889     if (webView->_gestureController) {
890         WebCore::Color color = webView->_gestureController->backgroundColorForCurrentSnapshot();
891         if (color.isValid())
892             return color;
893     }
894
895     return webView->_page->pageExtendedBackgroundColor();
896 }
897
898 static WebCore::Color scrollViewBackgroundColor(WKWebView *webView)
899 {
900     if (!webView.opaque)
901         return WebCore::Color::transparent;
902
903     WebCore::Color color = baseScrollViewBackgroundColor(webView);
904
905     if (!color.isValid())
906         color = WebCore::Color::white;
907
908     CGFloat zoomScale = contentZoomScale(webView);
909     CGFloat minimumZoomScale = [webView->_scrollView minimumZoomScale];
910     if (zoomScale < minimumZoomScale) {
911         CGFloat slope = 12;
912         CGFloat opacity = std::max<CGFloat>(1 - slope * (minimumZoomScale - zoomScale), 0);
913         color = WebCore::colorWithOverrideAlpha(color.rgb(), opacity);
914     }
915
916     return color;
917 }
918
919 - (void)_updateScrollViewBackground
920 {
921     WebCore::Color color = scrollViewBackgroundColor(self);
922
923     if (_scrollViewBackgroundColor == color)
924         return;
925
926     _scrollViewBackgroundColor = color;
927
928     auto uiBackgroundColor = adoptNS([[UIColor alloc] initWithCGColor:cachedCGColor(color)]);
929     [_scrollView setBackgroundColor:uiBackgroundColor.get()];
930
931     // Update the indicator style based on the lightness/darkness of the background color.
932     double hue, saturation, lightness;
933     color.getHSL(hue, saturation, lightness);
934     if (lightness <= .5 && color.alpha() > 0)
935         [_scrollView setIndicatorStyle:UIScrollViewIndicatorStyleWhite];
936     else
937         [_scrollView setIndicatorStyle:UIScrollViewIndicatorStyleDefault];
938 }
939
940 - (CGPoint)_adjustedContentOffset:(CGPoint)point
941 {
942     CGPoint result = point;
943     UIEdgeInsets contentInset = [self _computedContentInset];
944
945     result.x -= contentInset.left;
946     result.y -= contentInset.top;
947
948     return result;
949 }
950
951 - (UIEdgeInsets)_computedContentInset
952 {
953     if (_haveSetObscuredInsets)
954         return _obscuredInsets;
955
956     return [_scrollView contentInset];
957 }
958
959 - (void)_processDidExit
960 {
961     if (!_customContentView && _dynamicViewportUpdateMode != DynamicViewportUpdateMode::NotResizing) {
962         NSUInteger indexOfResizeAnimationView = [[_scrollView subviews] indexOfObject:_resizeAnimationView.get()];
963         [_scrollView insertSubview:_contentView.get() atIndex:indexOfResizeAnimationView];
964         [_scrollView insertSubview:[_contentView unscaledView] atIndex:indexOfResizeAnimationView + 1];
965         [_resizeAnimationView removeFromSuperview];
966         _resizeAnimationView = nil;
967
968         _resizeAnimationTransformAdjustments = CATransform3DIdentity;
969     }
970     [_contentView setFrame:self.bounds];
971     [_scrollView setBackgroundColor:[UIColor whiteColor]];
972     [_scrollView setContentOffset:[self _adjustedContentOffset:CGPointZero]];
973     [_scrollView setZoomScale:1];
974
975     _viewportMetaTagWidth = WebCore::ViewportArguments::ValueAuto;
976     _initialScaleFactor = 1;
977     _hasCommittedLoadForMainFrame = NO;
978     _needsResetViewStateAfterCommitLoadForMainFrame = NO;
979     _dynamicViewportUpdateMode = DynamicViewportUpdateMode::NotResizing;
980     [_contentView setHidden:NO];
981     _needsToRestoreExposedRect = NO;
982     _needsToRestoreUnobscuredCenter = NO;
983     _scrollViewBackgroundColor = WebCore::Color();
984     _delayUpdateVisibleContentRects = NO;
985     _hadDelayedUpdateVisibleContentRects = NO;
986 }
987
988 - (void)_didCommitLoadForMainFrame
989 {
990     _firstPaintAfterCommitLoadTransactionID = downcast<WebKit::RemoteLayerTreeDrawingAreaProxy>(*_page->drawingArea()).nextLayerTreeTransactionID();
991
992     _hasCommittedLoadForMainFrame = YES;
993     _needsResetViewStateAfterCommitLoadForMainFrame = YES;
994 }
995
996 static CGPoint contentOffsetBoundedInValidRange(UIScrollView *scrollView, CGPoint contentOffset)
997 {
998     UIEdgeInsets contentInsets = scrollView.contentInset;
999     CGSize contentSize = scrollView.contentSize;
1000     CGSize scrollViewSize = scrollView.bounds.size;
1001
1002     CGFloat maxHorizontalOffset = contentSize.width + contentInsets.right - scrollViewSize.width;
1003     contentOffset.x = std::min(maxHorizontalOffset, contentOffset.x);
1004     contentOffset.x = std::max(-contentInsets.left, contentOffset.x);
1005
1006     CGFloat maxVerticalOffset = contentSize.height + contentInsets.bottom - scrollViewSize.height;
1007     contentOffset.y = std::min(maxVerticalOffset, contentOffset.y);
1008     contentOffset.y = std::max(-contentInsets.top, contentOffset.y);
1009     return contentOffset;
1010 }
1011
1012 static void changeContentOffsetBoundedInValidRange(UIScrollView *scrollView, WebCore::FloatPoint contentOffset)
1013 {
1014     scrollView.contentOffset = contentOffsetBoundedInValidRange(scrollView, contentOffset);
1015 }
1016
1017 - (WebCore::FloatRect)visibleRectInViewCoordinates
1018 {
1019     WebCore::FloatRect bounds = self.bounds;
1020     bounds.moveBy([_scrollView contentOffset]);
1021     WebCore::FloatRect contentViewBounds = [_contentView bounds];
1022     bounds.intersect(contentViewBounds);
1023     return bounds;
1024 }
1025
1026 // WebCore stores the page scale factor as float instead of double. When we get a scale from WebCore,
1027 // we need to ignore differences that are within a small rounding error on floats.
1028 static inline bool areEssentiallyEqualAsFloat(float a, float b)
1029 {
1030     return WTF::areEssentiallyEqual(a, b);
1031 }
1032
1033 - (void)_didCommitLayerTree:(const WebKit::RemoteLayerTreeTransaction&)layerTreeTransaction
1034 {
1035     if (_customContentView)
1036         return;
1037
1038     if (_dynamicViewportUpdateMode != DynamicViewportUpdateMode::NotResizing) {
1039         if (layerTreeTransaction.transactionID() >= _resizeAnimationTransformTransactionID) {
1040             [_resizeAnimationView layer].sublayerTransform = _resizeAnimationTransformAdjustments;
1041             if (_dynamicViewportUpdateMode == DynamicViewportUpdateMode::ResizingWithDocumentHidden) {
1042                 [_contentView setHidden:NO];
1043                 [self _endAnimatedResize];
1044             }
1045         }
1046         return;
1047     }
1048
1049     CGSize newContentSize = roundScrollViewContentSize(*_page, [_contentView frame].size);
1050     [_scrollView _setContentSizePreservingContentOffsetDuringRubberband:newContentSize];
1051
1052     [_scrollView setMinimumZoomScale:layerTreeTransaction.minimumScaleFactor()];
1053     [_scrollView setMaximumZoomScale:layerTreeTransaction.maximumScaleFactor()];
1054     [_scrollView setZoomEnabled:layerTreeTransaction.allowsUserScaling()];
1055     if (!layerTreeTransaction.scaleWasSetByUIProcess() && ![_scrollView isZooming] && ![_scrollView isZoomBouncing] && ![_scrollView _isAnimatingZoom])
1056         [_scrollView setZoomScale:layerTreeTransaction.pageScaleFactor()];
1057
1058     _viewportMetaTagWidth = layerTreeTransaction.viewportMetaTagWidth();
1059     _initialScaleFactor = layerTreeTransaction.initialScaleFactor();
1060     if (![_contentView _mayDisableDoubleTapGesturesDuringSingleTap])
1061         [_contentView _setDoubleTapGesturesEnabled:self._allowsDoubleTapGestures];
1062
1063     [self _updateScrollViewBackground];
1064
1065     if (_gestureController)
1066         _gestureController->setRenderTreeSize(layerTreeTransaction.renderTreeSize());
1067
1068     if (_needsResetViewStateAfterCommitLoadForMainFrame && layerTreeTransaction.transactionID() >= _firstPaintAfterCommitLoadTransactionID) {
1069         _needsResetViewStateAfterCommitLoadForMainFrame = NO;
1070         [_scrollView setContentOffset:[self _adjustedContentOffset:CGPointZero]];
1071         [self _updateVisibleContentRects];
1072         if (_observedRenderingProgressEvents & _WKRenderingProgressEventFirstPaint)
1073             _navigationState->didFirstPaint();
1074     }
1075
1076     bool isTransactionAfterPageRestore = layerTreeTransaction.transactionID() >= _firstTransactionIDAfterPageRestore;
1077
1078     if (_needsToRestoreExposedRect && isTransactionAfterPageRestore) {
1079         _needsToRestoreExposedRect = NO;
1080
1081         if (areEssentiallyEqualAsFloat(contentZoomScale(self), _scaleToRestore)) {
1082             WebCore::FloatPoint exposedPosition = _exposedRectToRestore.location();
1083             exposedPosition.scale(_scaleToRestore, _scaleToRestore);
1084
1085             changeContentOffsetBoundedInValidRange(_scrollView.get(), exposedPosition);
1086             if (_gestureController)
1087                 _gestureController->didRestoreScrollPosition();
1088         }
1089         [self _updateVisibleContentRects];
1090     }
1091
1092     if (_needsToRestoreUnobscuredCenter && isTransactionAfterPageRestore) {
1093         _needsToRestoreUnobscuredCenter = NO;
1094
1095         if (areEssentiallyEqualAsFloat(contentZoomScale(self), _scaleToRestore)) {
1096             CGRect unobscuredRect = UIEdgeInsetsInsetRect(self.bounds, _obscuredInsets);
1097             WebCore::FloatSize unobscuredContentSizeAtNewScale(unobscuredRect.size.width / _scaleToRestore, unobscuredRect.size.height / _scaleToRestore);
1098             WebCore::FloatPoint topLeftInDocumentCoordinates(_unobscuredCenterToRestore.x() - unobscuredContentSizeAtNewScale.width() / 2, _unobscuredCenterToRestore.y() - unobscuredContentSizeAtNewScale.height() / 2);
1099
1100             topLeftInDocumentCoordinates.scale(_scaleToRestore, _scaleToRestore);
1101             topLeftInDocumentCoordinates.moveBy(WebCore::FloatPoint(-_obscuredInsets.left, -_obscuredInsets.top));
1102
1103             changeContentOffsetBoundedInValidRange(_scrollView.get(), topLeftInDocumentCoordinates);
1104             if (_gestureController)
1105                 _gestureController->didRestoreScrollPosition();
1106         }
1107         [self _updateVisibleContentRects];
1108     }
1109     
1110     if (WebKit::RemoteLayerTreeScrollingPerformanceData* scrollPerfData = _page->scrollingPerformanceData())
1111         scrollPerfData->didCommitLayerTree([self visibleRectInViewCoordinates]);
1112 }
1113
1114 - (void)_dynamicViewportUpdateChangedTargetToScale:(double)newScale position:(CGPoint)newScrollPosition nextValidLayerTreeTransactionID:(uint64_t)nextValidLayerTreeTransactionID
1115 {
1116     if (_dynamicViewportUpdateMode != DynamicViewportUpdateMode::NotResizing) {
1117         CGFloat animatingScaleTarget = [[_resizeAnimationView layer] transform].m11;
1118         double currentTargetScale = animatingScaleTarget * [[_contentView layer] transform].m11;
1119         double scale = newScale / currentTargetScale;
1120         _resizeAnimationTransformAdjustments = CATransform3DMakeScale(scale, scale, 1);
1121
1122         CGPoint newContentOffset = [self _adjustedContentOffset:CGPointMake(newScrollPosition.x * newScale, newScrollPosition.y * newScale)];
1123         CGPoint currentContentOffset = [_scrollView contentOffset];
1124
1125         _resizeAnimationTransformAdjustments.m41 = (currentContentOffset.x - newContentOffset.x) / animatingScaleTarget;
1126         _resizeAnimationTransformAdjustments.m42 = (currentContentOffset.y - newContentOffset.y) / animatingScaleTarget;
1127         _resizeAnimationTransformTransactionID = nextValidLayerTreeTransactionID;
1128     }
1129 }
1130
1131 - (void)_couldNotRestorePageState
1132 {
1133     // The gestureController may be waiting for the scroll position to be restored
1134     // in order to remove the swipe snapshot. Since the scroll position could not be
1135     // restored, tell the gestureController it was restored so that it no longer waits
1136     // for it.
1137     if (_gestureController)
1138         _gestureController->didRestoreScrollPosition();
1139 }
1140
1141 - (void)_restorePageStateToExposedRect:(WebCore::FloatRect)exposedRect scale:(double)scale
1142 {
1143     if (_dynamicViewportUpdateMode != DynamicViewportUpdateMode::NotResizing)
1144         return;
1145
1146     if (_customContentView)
1147         return;
1148
1149     _needsToRestoreUnobscuredCenter = NO;
1150     _needsToRestoreExposedRect = YES;
1151     _firstTransactionIDAfterPageRestore = downcast<WebKit::RemoteLayerTreeDrawingAreaProxy>(*_page->drawingArea()).nextLayerTreeTransactionID();
1152     _exposedRectToRestore = exposedRect;
1153     _scaleToRestore = scale;
1154 }
1155
1156 - (void)_restorePageStateToUnobscuredCenter:(WebCore::FloatPoint)center scale:(double)scale
1157 {
1158     if (_dynamicViewportUpdateMode != DynamicViewportUpdateMode::NotResizing)
1159         return;
1160
1161     if (_customContentView)
1162         return;
1163
1164     _needsToRestoreExposedRect = NO;
1165     _needsToRestoreUnobscuredCenter = YES;
1166     _firstTransactionIDAfterPageRestore = downcast<WebKit::RemoteLayerTreeDrawingAreaProxy>(*_page->drawingArea()).nextLayerTreeTransactionID();
1167     _unobscuredCenterToRestore = center;
1168     _scaleToRestore = scale;
1169 }
1170
1171 - (PassRefPtr<WebKit::ViewSnapshot>)_takeViewSnapshot
1172 {
1173     float deviceScale = WebCore::screenScaleFactor();
1174     WebCore::FloatSize snapshotSize(self.bounds.size);
1175     snapshotSize.scale(deviceScale, deviceScale);
1176
1177     CATransform3D transform = CATransform3DMakeScale(deviceScale, deviceScale, 1);
1178
1179 #if USE(IOSURFACE)
1180     auto surface = WebCore::IOSurface::create(WebCore::expandedIntSize(snapshotSize), WebCore::ColorSpaceSRGB);
1181     CARenderServerRenderLayerWithTransform(MACH_PORT_NULL, self.layer.context.contextId, reinterpret_cast<uint64_t>(self.layer), surface->surface(), 0, 0, &transform);
1182
1183     RefPtr<WebKit::ViewSnapshot> viewSnapshot = WebKit::ViewSnapshot::create(nullptr);
1184     WebCore::IOSurface::convertToFormat(WTF::move(surface), WebCore::IOSurface::Format::YUV422, [viewSnapshot](std::unique_ptr<WebCore::IOSurface> convertedSurface) {
1185         viewSnapshot->setSurface(WTF::move(convertedSurface));
1186     });
1187
1188     return viewSnapshot;
1189 #else
1190     uint32_t slotID = [WebKit::ViewSnapshotStore::snapshottingContext() createImageSlot:snapshotSize hasAlpha:YES];
1191
1192     if (!slotID)
1193         return nullptr;
1194
1195     CARenderServerCaptureLayerWithTransform(MACH_PORT_NULL, self.layer.context.contextId, (uint64_t)self.layer, slotID, 0, 0, &transform);
1196     WebCore::IntSize imageSize = WebCore::expandedIntSize(WebCore::FloatSize(snapshotSize));
1197     return WebKit::ViewSnapshot::create(slotID, imageSize, imageSize.width() * imageSize.height() * 4);
1198 #endif
1199 }
1200
1201 - (void)_zoomToPoint:(WebCore::FloatPoint)point atScale:(double)scale animated:(BOOL)animated
1202 {
1203     CFTimeInterval duration = 0;
1204     CGFloat zoomScale = contentZoomScale(self);
1205
1206     if (animated) {
1207         const double maximumZoomDuration = 0.4;
1208         const double minimumZoomDuration = 0.1;
1209         const double zoomDurationFactor = 0.3;
1210
1211         duration = std::min(fabs(log(zoomScale) - log(scale)) * zoomDurationFactor + minimumZoomDuration, maximumZoomDuration);
1212     }
1213
1214     if (scale != zoomScale)
1215         _page->willStartUserTriggeredZooming();
1216
1217     [_scrollView _zoomToCenter:point scale:scale duration:duration];
1218 }
1219
1220 - (void)_zoomToRect:(WebCore::FloatRect)targetRect atScale:(double)scale origin:(WebCore::FloatPoint)origin animated:(BOOL)animated
1221 {
1222     // FIXME: Some of this could be shared with _scrollToRect.
1223     const double visibleRectScaleChange = contentZoomScale(self) / scale;
1224     const WebCore::FloatRect visibleRect([self convertRect:self.bounds toView:self._currentContentView]);
1225     const WebCore::FloatRect unobscuredRect([self _contentRectForUserInteraction]);
1226
1227     const WebCore::FloatSize topLeftObscuredInsetAfterZoom((unobscuredRect.minXMinYCorner() - visibleRect.minXMinYCorner()) * visibleRectScaleChange);
1228     const WebCore::FloatSize bottomRightObscuredInsetAfterZoom((visibleRect.maxXMaxYCorner() - unobscuredRect.maxXMaxYCorner()) * visibleRectScaleChange);
1229
1230     const WebCore::FloatSize unobscuredRectSizeAfterZoom(unobscuredRect.size() * visibleRectScaleChange);
1231
1232     // Center to the target rect.
1233     WebCore::FloatPoint unobscuredRectLocationAfterZoom = targetRect.location() - (unobscuredRectSizeAfterZoom - targetRect.size()) * 0.5;
1234
1235     // Center to the tap point instead in case the target rect won't fit in a direction.
1236     if (targetRect.width() > unobscuredRectSizeAfterZoom.width())
1237         unobscuredRectLocationAfterZoom.setX(origin.x() - unobscuredRectSizeAfterZoom.width() / 2);
1238     if (targetRect.height() > unobscuredRectSizeAfterZoom.height())
1239         unobscuredRectLocationAfterZoom.setY(origin.y() - unobscuredRectSizeAfterZoom.height() / 2);
1240
1241     // We have computed where we want the unobscured rect to be. Now adjust for the obscuring insets.
1242     WebCore::FloatRect visibleRectAfterZoom(unobscuredRectLocationAfterZoom, unobscuredRectSizeAfterZoom);
1243     visibleRectAfterZoom.move(-topLeftObscuredInsetAfterZoom);
1244     visibleRectAfterZoom.expand(topLeftObscuredInsetAfterZoom + bottomRightObscuredInsetAfterZoom);
1245
1246     [self _zoomToPoint:visibleRectAfterZoom.center() atScale:scale animated:animated];
1247 }
1248
1249 static WebCore::FloatPoint constrainContentOffset(WebCore::FloatPoint contentOffset, WebCore::FloatSize contentSize, WebCore::FloatSize unobscuredContentSize)
1250 {
1251     WebCore::FloatSize maximumContentOffset = contentSize - unobscuredContentSize;
1252     contentOffset = contentOffset.shrunkTo(WebCore::FloatPoint(maximumContentOffset.width(), maximumContentOffset.height()));
1253     contentOffset = contentOffset.expandedTo(WebCore::FloatPoint());
1254     return contentOffset;
1255 }
1256
1257 - (void)_scrollToContentOffset:(WebCore::FloatPoint)contentOffsetInPageCoordinates scrollOrigin:(WebCore::IntPoint)scrollOrigin
1258 {
1259     if (_dynamicViewportUpdateMode != DynamicViewportUpdateMode::NotResizing)
1260         return;
1261
1262     WebCore::FloatPoint contentOffsetRespectingOrigin = scrollOrigin + toFloatSize(contentOffsetInPageCoordinates);
1263
1264     WebCore::FloatPoint scaledOffset = contentOffsetRespectingOrigin;
1265     CGFloat zoomScale = contentZoomScale(self);
1266     scaledOffset.scale(zoomScale, zoomScale);
1267
1268     CGPoint contentOffsetInScrollViewCoordinates = [self _adjustedContentOffset:scaledOffset];
1269     contentOffsetInScrollViewCoordinates = contentOffsetBoundedInValidRange(_scrollView.get(), contentOffsetInScrollViewCoordinates);
1270
1271     [_scrollView _stopScrollingAndZoomingAnimations];
1272
1273     if (!CGPointEqualToPoint(contentOffsetInScrollViewCoordinates, [_scrollView contentOffset]))
1274         [_scrollView setContentOffset:contentOffsetInScrollViewCoordinates];
1275     else {
1276         // If we haven't changed anything, there would not be any VisibleContentRect update sent to the content.
1277         // The WebProcess would keep the invalid contentOffset as its scroll position.
1278         // To synchronize the WebProcess with what is on screen, we send the VisibleContentRect again.
1279         _page->resendLastVisibleContentRects();
1280     }
1281 }
1282
1283 - (BOOL)_scrollToRect:(WebCore::FloatRect)targetRect origin:(WebCore::FloatPoint)origin minimumScrollDistance:(float)minimumScrollDistance
1284 {
1285     WebCore::FloatRect unobscuredContentRect([self _contentRectForUserInteraction]);
1286     WebCore::FloatPoint unobscuredContentOffset = unobscuredContentRect.location();
1287     WebCore::FloatSize contentSize([self._currentContentView bounds].size);
1288
1289     // Center the target rect in the scroll view.
1290     // If the target doesn't fit in the scroll view, center on the gesture location instead.
1291     WebCore::FloatPoint newUnobscuredContentOffset;
1292     if (targetRect.width() <= unobscuredContentRect.width())
1293         newUnobscuredContentOffset.setX(targetRect.x() - (unobscuredContentRect.width() - targetRect.width()) / 2);
1294     else
1295         newUnobscuredContentOffset.setX(origin.x() - unobscuredContentRect.width() / 2);
1296     if (targetRect.height() <= unobscuredContentRect.height())
1297         newUnobscuredContentOffset.setY(targetRect.y() - (unobscuredContentRect.height() - targetRect.height()) / 2);
1298     else
1299         newUnobscuredContentOffset.setY(origin.y() - unobscuredContentRect.height() / 2);
1300     newUnobscuredContentOffset = constrainContentOffset(newUnobscuredContentOffset, contentSize, unobscuredContentRect.size());
1301
1302     if (unobscuredContentOffset == newUnobscuredContentOffset) {
1303         if (targetRect.width() > unobscuredContentRect.width())
1304             newUnobscuredContentOffset.setX(origin.x() - unobscuredContentRect.width() / 2);
1305         if (targetRect.height() > unobscuredContentRect.height())
1306             newUnobscuredContentOffset.setY(origin.y() - unobscuredContentRect.height() / 2);
1307         newUnobscuredContentOffset = constrainContentOffset(newUnobscuredContentOffset, contentSize, unobscuredContentRect.size());
1308     }
1309
1310     WebCore::FloatSize scrollViewOffsetDelta = newUnobscuredContentOffset - unobscuredContentOffset;
1311     scrollViewOffsetDelta.scale(contentZoomScale(self));
1312
1313     float scrollDistance = scrollViewOffsetDelta.diagonalLength();
1314     if (scrollDistance < minimumScrollDistance)
1315         return false;
1316
1317     [_contentView willStartZoomOrScroll];
1318
1319     [_scrollView setContentOffset:([_scrollView contentOffset] + scrollViewOffsetDelta) animated:YES];
1320     return true;
1321 }
1322
1323 - (void)_scrollByContentOffset:(WebCore::FloatPoint)contentOffsetDelta
1324 {
1325     WebCore::FloatPoint scaledOffsetDelta = contentOffsetDelta;
1326     CGFloat zoomScale = contentZoomScale(self);
1327     scaledOffsetDelta.scale(zoomScale, zoomScale);
1328
1329     CGPoint currentOffset = [_scrollView _isAnimatingScroll] ? [_scrollView _animatedTargetOffset] : [_scrollView contentOffset];
1330     CGPoint boundedOffset = contentOffsetBoundedInValidRange(_scrollView.get(), currentOffset + scaledOffsetDelta);
1331
1332     if (CGPointEqualToPoint(boundedOffset, currentOffset))
1333         return;
1334     [_contentView willStartZoomOrScroll];
1335     [_scrollView setContentOffset:boundedOffset animated:YES];
1336 }
1337
1338 - (void)_zoomOutWithOrigin:(WebCore::FloatPoint)origin animated:(BOOL)animated
1339 {
1340     [self _zoomToPoint:origin atScale:[_scrollView minimumZoomScale] animated:animated];
1341 }
1342
1343 - (void)_zoomToInitialScaleWithOrigin:(WebCore::FloatPoint)origin animated:(BOOL)animated
1344 {
1345     ASSERT(_initialScaleFactor > 0);
1346     [self _zoomToPoint:origin atScale:_initialScaleFactor animated:animated];
1347 }
1348
1349 // focusedElementRect and selectionRect are both in document coordinates.
1350 - (void)_zoomToFocusRect:(WebCore::FloatRect)focusedElementRectInDocumentCoordinates selectionRect:(WebCore::FloatRect)selectionRectInDocumentCoordinates fontSize:(float)fontSize minimumScale:(double)minimumScale maximumScale:(double)maximumScale allowScaling:(BOOL)allowScaling forceScroll:(BOOL)forceScroll
1351 {
1352     const double WKWebViewStandardFontSize = 16;
1353     const double kMinimumHeightToShowContentAboveKeyboard = 106;
1354     const CFTimeInterval UIWebFormAnimationDuration = 0.25;
1355     const double CaretOffsetFromWindowEdge = 20;
1356
1357     // Zoom around the element's bounding frame. We use a "standard" size to determine the proper frame.
1358     double scale = allowScaling ? std::min(std::max(WKWebViewStandardFontSize / fontSize, minimumScale), maximumScale) : contentZoomScale(self);
1359     CGFloat documentWidth = [_contentView bounds].size.width;
1360     scale = CGRound(documentWidth * scale) / documentWidth;
1361
1362     UIWindow *window = [_scrollView window];
1363
1364     WebCore::FloatRect focusedElementRectInNewScale = focusedElementRectInDocumentCoordinates;
1365     focusedElementRectInNewScale.scale(scale);
1366     focusedElementRectInNewScale.moveBy([_contentView frame].origin);
1367
1368     // Find the portion of the view that is visible on the screen.
1369     UIViewController *topViewController = [[[_scrollView _viewControllerForAncestor] _rootAncestorViewController] _viewControllerForSupportedInterfaceOrientations];
1370     UIView *fullScreenView = topViewController.view;
1371     if (!fullScreenView)
1372         fullScreenView = window;
1373
1374     CGRect unobscuredScrollViewRectInWebViewCoordinates = UIEdgeInsetsInsetRect([self bounds], _obscuredInsets);
1375     CGRect visibleScrollViewBoundsInWebViewCoordinates = CGRectIntersection(unobscuredScrollViewRectInWebViewCoordinates, [fullScreenView convertRect:[fullScreenView bounds] toView:self]);
1376     CGRect formAssistantFrameInWebViewCoordinates = [window convertRect:_inputViewBounds toView:self];
1377     CGRect intersectionBetweenScrollViewAndFormAssistant = CGRectIntersection(visibleScrollViewBoundsInWebViewCoordinates, formAssistantFrameInWebViewCoordinates);
1378     CGSize visibleSize = visibleScrollViewBoundsInWebViewCoordinates.size;
1379
1380     CGFloat visibleOffsetFromTop = 0;
1381     if (!CGRectIsEmpty(intersectionBetweenScrollViewAndFormAssistant)) {
1382         CGFloat heightVisibleAboveFormAssistant = CGRectGetMinY(intersectionBetweenScrollViewAndFormAssistant) - CGRectGetMinY(visibleScrollViewBoundsInWebViewCoordinates);
1383         CGFloat heightVisibleBelowFormAssistant = CGRectGetMaxY(visibleScrollViewBoundsInWebViewCoordinates) - CGRectGetMaxY(intersectionBetweenScrollViewAndFormAssistant);
1384
1385         if (heightVisibleAboveFormAssistant >= kMinimumHeightToShowContentAboveKeyboard || heightVisibleBelowFormAssistant < heightVisibleAboveFormAssistant)
1386             visibleSize.height = heightVisibleAboveFormAssistant;
1387         else {
1388             visibleSize.height = heightVisibleBelowFormAssistant;
1389             visibleOffsetFromTop = CGRectGetMaxY(intersectionBetweenScrollViewAndFormAssistant) - CGRectGetMinY(visibleScrollViewBoundsInWebViewCoordinates);
1390         }
1391     }
1392
1393     BOOL selectionRectIsNotNull = !selectionRectInDocumentCoordinates.isZero();
1394     if (!forceScroll) {
1395         CGRect currentlyVisibleRegionInWebViewCoordinates;
1396         currentlyVisibleRegionInWebViewCoordinates.origin = unobscuredScrollViewRectInWebViewCoordinates.origin;
1397         currentlyVisibleRegionInWebViewCoordinates.origin.y += visibleOffsetFromTop;
1398         currentlyVisibleRegionInWebViewCoordinates.size = visibleSize;
1399
1400         // Don't bother scrolling if the entire node is already visible, whether or not we got a selectionRect.
1401         if (CGRectContainsRect(currentlyVisibleRegionInWebViewCoordinates, [self convertRect:focusedElementRectInDocumentCoordinates fromView:_contentView.get()]))
1402             return;
1403
1404         // Don't bother scrolling if we have a valid selectionRect and it is already visible.
1405         if (selectionRectIsNotNull && CGRectContainsRect(currentlyVisibleRegionInWebViewCoordinates, [self convertRect:selectionRectInDocumentCoordinates fromView:_contentView.get()]))
1406             return;
1407     }
1408
1409     // We want to zoom to the left/top corner of the DOM node, with as much spacing on all sides as we
1410     // can get based on the visible area after zooming (workingFrame).  The spacing in either dimension is half the
1411     // difference between the size of the DOM node and the size of the visible frame.
1412     CGFloat horizontalSpaceInWebViewCoordinates = std::max((visibleSize.width - focusedElementRectInNewScale.width()) / 2.0, 0.0);
1413     CGFloat verticalSpaceInWebViewCoordinates = std::max((visibleSize.height - focusedElementRectInNewScale.height()) / 2.0, 0.0);
1414
1415     CGPoint topLeft;
1416     topLeft.x = focusedElementRectInNewScale.x() - horizontalSpaceInWebViewCoordinates;
1417     topLeft.y = focusedElementRectInNewScale.y() - verticalSpaceInWebViewCoordinates - visibleOffsetFromTop;
1418
1419     CGFloat minimumAllowableHorizontalOffsetInWebViewCoordinates = -INFINITY;
1420     CGFloat minimumAllowableVerticalOffsetInWebViewCoordinates = -INFINITY;
1421     if (selectionRectIsNotNull) {
1422         WebCore::FloatRect selectionRectInNewScale = selectionRectInDocumentCoordinates;
1423         selectionRectInNewScale.scale(scale);
1424         selectionRectInNewScale.moveBy([_contentView frame].origin);
1425         minimumAllowableHorizontalOffsetInWebViewCoordinates = CGRectGetMaxX(selectionRectInNewScale) + CaretOffsetFromWindowEdge - visibleSize.width;
1426         minimumAllowableVerticalOffsetInWebViewCoordinates = CGRectGetMaxY(selectionRectInNewScale) + CaretOffsetFromWindowEdge - visibleSize.height - visibleOffsetFromTop;
1427     }
1428
1429     WebCore::FloatRect documentBoundsInNewScale = [_contentView bounds];
1430     documentBoundsInNewScale.scale(scale);
1431     documentBoundsInNewScale.moveBy([_contentView frame].origin);
1432
1433     // Constrain the left edge in document coordinates so that:
1434     //  - it isn't so small that the scrollVisibleRect isn't visible on the screen
1435     //  - it isn't so great that the document's right edge is less than the right edge of the screen
1436     if (selectionRectIsNotNull && topLeft.x < minimumAllowableHorizontalOffsetInWebViewCoordinates)
1437         topLeft.x = minimumAllowableHorizontalOffsetInWebViewCoordinates;
1438     else {
1439         CGFloat maximumAllowableHorizontalOffset = CGRectGetMaxX(documentBoundsInNewScale) - visibleSize.width;
1440         if (topLeft.x > maximumAllowableHorizontalOffset)
1441             topLeft.x = maximumAllowableHorizontalOffset;
1442     }
1443
1444     // Constrain the top edge in document coordinates so that:
1445     //  - it isn't so small that the scrollVisibleRect isn't visible on the screen
1446     //  - it isn't so great that the document's bottom edge is higher than the top of the form assistant
1447     if (selectionRectIsNotNull && topLeft.y < minimumAllowableVerticalOffsetInWebViewCoordinates)
1448         topLeft.y = minimumAllowableVerticalOffsetInWebViewCoordinates;
1449     else {
1450         CGFloat maximumAllowableVerticalOffset = CGRectGetMaxY(documentBoundsInNewScale) - visibleSize.height;
1451         if (topLeft.y > maximumAllowableVerticalOffset)
1452             topLeft.y = maximumAllowableVerticalOffset;
1453     }
1454
1455     WebCore::FloatPoint newCenter = CGPointMake(topLeft.x + unobscuredScrollViewRectInWebViewCoordinates.size.width / 2.0, topLeft.y + unobscuredScrollViewRectInWebViewCoordinates.size.height / 2.0);
1456
1457     if (scale != contentZoomScale(self))
1458         _page->willStartUserTriggeredZooming();
1459
1460     // The newCenter has been computed in the new scale, but _zoomToCenter expected the center to be in the original scale.
1461     newCenter.scale(1 / scale, 1 / scale);
1462     [_scrollView _zoomToCenter:newCenter
1463                         scale:scale
1464                      duration:UIWebFormAnimationDuration
1465                         force:YES];
1466 }
1467
1468 - (CGFloat)_targetContentZoomScaleForRect:(const WebCore::FloatRect&)targetRect currentScale:(double)currentScale fitEntireRect:(BOOL)fitEntireRect minimumScale:(double)minimumScale maximumScale:(double)maximumScale
1469 {
1470     WebCore::FloatSize unobscuredContentSize([self _contentRectForUserInteraction].size);
1471     double horizontalScale = unobscuredContentSize.width() * currentScale / targetRect.width();
1472     double verticalScale = unobscuredContentSize.height() * currentScale / targetRect.height();
1473
1474     horizontalScale = std::min(std::max(horizontalScale, minimumScale), maximumScale);
1475     verticalScale = std::min(std::max(verticalScale, minimumScale), maximumScale);
1476
1477     return fitEntireRect ? std::min(horizontalScale, verticalScale) : horizontalScale;
1478 }
1479
1480 - (BOOL)_zoomToRect:(WebCore::FloatRect)targetRect withOrigin:(WebCore::FloatPoint)origin fitEntireRect:(BOOL)fitEntireRect minimumScale:(double)minimumScale maximumScale:(double)maximumScale minimumScrollDistance:(float)minimumScrollDistance
1481 {
1482     const float maximumScaleFactorDeltaForPanScroll = 0.02;
1483
1484     double currentScale = contentZoomScale(self);
1485     double targetScale = [self _targetContentZoomScaleForRect:targetRect currentScale:currentScale fitEntireRect:fitEntireRect minimumScale:minimumScale maximumScale:maximumScale];
1486
1487     if (fabs(targetScale - currentScale) < maximumScaleFactorDeltaForPanScroll) {
1488         if ([self _scrollToRect:targetRect origin:origin minimumScrollDistance:minimumScrollDistance])
1489             return true;
1490     } else if (targetScale != currentScale) {
1491         [self _zoomToRect:targetRect atScale:targetScale origin:origin animated:YES];
1492         return true;
1493     }
1494     
1495     return false;
1496 }
1497
1498 - (void)didMoveToWindow
1499 {
1500     _page->viewStateDidChange(WebCore::ViewState::AllFlags);
1501 }
1502
1503 - (void)setOpaque:(BOOL)opaque
1504 {
1505     BOOL oldOpaque = self.opaque;
1506
1507     [super setOpaque:opaque];
1508     [_contentView setOpaque:opaque];
1509
1510     if (oldOpaque == opaque)
1511         return;
1512
1513     _page->setDrawsBackground(opaque);
1514     [self _updateScrollViewBackground];
1515 }
1516
1517 - (void)setBackgroundColor:(UIColor *)backgroundColor
1518 {
1519     [super setBackgroundColor:backgroundColor];
1520     [_contentView setBackgroundColor:backgroundColor];
1521 }
1522
1523 #pragma mark - UIScrollViewDelegate
1524
1525 - (BOOL)usesStandardContentView
1526 {
1527     return !_customContentView;
1528 }
1529
1530 - (CGSize)scrollView:(UIScrollView*)scrollView contentSizeForZoomScale:(CGFloat)scale withProposedSize:(CGSize)proposedSize
1531 {
1532     return roundScrollViewContentSize(*_page, proposedSize);
1533 }
1534
1535 - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
1536 {
1537     ASSERT(_scrollView == scrollView);
1538
1539     if (_customContentView)
1540         return _customContentView.get();
1541
1542     return _contentView.get();
1543 }
1544
1545 - (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view
1546 {
1547     if (![self usesStandardContentView])
1548         return;
1549
1550     if (scrollView.pinchGestureRecognizer.state == UIGestureRecognizerStateBegan) {
1551         _page->willStartUserTriggeredZooming();
1552         [_contentView scrollViewWillStartPanOrPinchGesture];
1553     }
1554     [_contentView willStartZoomOrScroll];
1555 }
1556
1557 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
1558 {
1559     if (![self usesStandardContentView])
1560         return;
1561
1562     if (scrollView.panGestureRecognizer.state == UIGestureRecognizerStateBegan)
1563         [_contentView scrollViewWillStartPanOrPinchGesture];
1564
1565     [_contentView willStartZoomOrScroll];
1566 #if ENABLE(CSS_SCROLL_SNAP) && ENABLE(ASYNC_SCROLLING)
1567     // FIXME: We will want to detect whether snapping will occur before beginning to drag. See WebPageProxy::didCommitLayerTree.
1568     WebKit::RemoteScrollingCoordinatorProxy* coordinator = _page->scrollingCoordinatorProxy();
1569     ASSERT(scrollView == _scrollView.get());
1570     CGFloat scrollDecelerationFactor = (coordinator && coordinator->shouldSetScrollViewDecelerationRateFast()) ? UIScrollViewDecelerationRateFast : [_scrollView preferredScrollDecelerationFactor];
1571     scrollView.horizontalScrollDecelerationFactor = scrollDecelerationFactor;
1572     scrollView.verticalScrollDecelerationFactor = scrollDecelerationFactor;
1573 #endif
1574 }
1575
1576 - (void)_didFinishScrolling
1577 {
1578     if (![self usesStandardContentView])
1579         return;
1580
1581     [self _updateVisibleContentRects];
1582     [_contentView didFinishScrolling];
1583 }
1584
1585 - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
1586 {
1587     // Work around <rdar://problem/16374753> by avoiding deceleration while
1588     // zooming. We'll animate to the right place once the zoom finishes.
1589     if ([scrollView isZooming])
1590         *targetContentOffset = [scrollView contentOffset];
1591 #if ENABLE(CSS_SCROLL_SNAP) && ENABLE(ASYNC_SCROLLING)
1592     if (WebKit::RemoteScrollingCoordinatorProxy* coordinator = _page->scrollingCoordinatorProxy()) {
1593         // FIXME: Here, I'm finding the maximum horizontal/vertical scroll offsets. There's probably a better way to do this.
1594         CGSize maxScrollOffsets = CGSizeMake(scrollView.contentSize.width - scrollView.bounds.size.width, scrollView.contentSize.height - scrollView.bounds.size.height);
1595         
1596         CGRect fullViewRect = self.bounds;
1597
1598         UIEdgeInsets contentInset;
1599
1600         id<WKUIDelegatePrivate> uiDelegatePrivate = static_cast<id <WKUIDelegatePrivate>>([self UIDelegate]);
1601         if ([uiDelegatePrivate respondsToSelector:@selector(_webView:finalObscuredInsetsForScrollView:withVelocity:targetContentOffset:)])
1602             contentInset = [uiDelegatePrivate _webView:self finalObscuredInsetsForScrollView:scrollView withVelocity:velocity targetContentOffset:targetContentOffset];
1603         else
1604             contentInset = [self _computedContentInset];
1605
1606         CGRect unobscuredRect = UIEdgeInsetsInsetRect(fullViewRect, contentInset);
1607         
1608         coordinator->adjustTargetContentOffsetForSnapping(maxScrollOffsets, velocity, unobscuredRect.origin.y, targetContentOffset);
1609     }
1610 #endif
1611 }
1612
1613 - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
1614 {
1615     // If we're decelerating, scroll offset will be updated when scrollViewDidFinishDecelerating: is called.
1616     if (!decelerate)
1617         [self _didFinishScrolling];
1618 }
1619
1620 - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
1621 {
1622     [self _didFinishScrolling];
1623 }
1624
1625 - (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView
1626 {
1627     [self _didFinishScrolling];
1628 }
1629
1630 - (void)scrollViewDidScroll:(UIScrollView *)scrollView
1631 {
1632     if (![self usesStandardContentView])
1633         [_customContentView scrollViewDidScroll:(UIScrollView *)scrollView];
1634
1635     [self _updateVisibleContentRects];
1636     
1637     if (WebKit::RemoteLayerTreeScrollingPerformanceData* scrollPerfData = _page->scrollingPerformanceData())
1638         scrollPerfData->didScroll([self visibleRectInViewCoordinates]);
1639 }
1640
1641 - (void)scrollViewDidZoom:(UIScrollView *)scrollView
1642 {
1643     [self _updateScrollViewBackground];
1644     [self _updateVisibleContentRects];
1645 }
1646
1647 - (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale
1648 {
1649     ASSERT(scrollView == _scrollView);
1650     [self _updateVisibleContentRects];
1651     [_contentView didZoomToScale:scale];
1652 }
1653
1654 - (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
1655 {
1656     [self _didFinishScrolling];
1657 }
1658
1659 - (void)_scrollViewDidInterruptDecelerating:(UIScrollView *)scrollView
1660 {
1661     if (![self usesStandardContentView])
1662         return;
1663
1664     [_contentView didInterruptScrolling];
1665     [self _updateVisibleContentRects];
1666 }
1667
1668 - (void)_frameOrBoundsChanged
1669 {
1670     CGRect bounds = self.bounds;
1671     [_scrollView setFrame:bounds];
1672
1673     if (_dynamicViewportUpdateMode == DynamicViewportUpdateMode::NotResizing) {
1674         if (!_overridesMinimumLayoutSize)
1675             _page->setViewportConfigurationMinimumLayoutSize(WebCore::FloatSize(bounds.size));
1676         if (!_overridesMaximumUnobscuredSize)
1677             _page->setMaximumUnobscuredSize(WebCore::FloatSize(bounds.size));
1678         if (WebKit::DrawingAreaProxy* drawingArea = _page->drawingArea())
1679             drawingArea->setSize(WebCore::IntSize(bounds.size), WebCore::IntSize(), WebCore::IntSize());
1680     }
1681
1682     [_customContentView web_setMinimumSize:bounds.size];
1683     [self _updateVisibleContentRects];
1684 }
1685
1686 // Unobscured content rect where the user can interact. When the keyboard is up, this should be the area above or below the keyboard, wherever there is enough space.
1687 - (CGRect)_contentRectForUserInteraction
1688 {
1689     // FIXME: handle split keyboard.
1690     UIEdgeInsets obscuredInsets = _obscuredInsets;
1691     obscuredInsets.bottom = std::max(_obscuredInsets.bottom, _inputViewBounds.size.height);
1692     CGRect unobscuredRect = UIEdgeInsetsInsetRect(self.bounds, obscuredInsets);
1693     return [self convertRect:unobscuredRect toView:self._currentContentView];
1694 }
1695
1696 // Ideally UIScrollView would expose this for us: <rdar://problem/21394567>.
1697 - (BOOL)_scrollViewIsRubberBanding
1698 {
1699     float deviceScaleFactor = _page->deviceScaleFactor();
1700
1701     CGPoint contentOffset = [_scrollView contentOffset];
1702     CGPoint boundedOffset = contentOffsetBoundedInValidRange(_scrollView.get(), contentOffset);
1703     return !pointsEqualInDevicePixels(contentOffset, boundedOffset, deviceScaleFactor);
1704 }
1705
1706 - (void)_updateVisibleContentRects
1707 {
1708     if (![self usesStandardContentView]) {
1709         [_customContentView web_computedContentInsetDidChange];
1710         return;
1711     }
1712
1713     if (_delayUpdateVisibleContentRects) {
1714         _hadDelayedUpdateVisibleContentRects = YES;
1715         return;
1716     }
1717
1718     if (_dynamicViewportUpdateMode != DynamicViewportUpdateMode::NotResizing
1719         || _needsResetViewStateAfterCommitLoadForMainFrame
1720         || [_scrollView isZoomBouncing]
1721         || _currentlyAdjustingScrollViewInsetsForKeyboard)
1722         return;
1723
1724     CGRect fullViewRect = self.bounds;
1725     CGRect visibleRectInContentCoordinates = _frozenVisibleContentRect ? _frozenVisibleContentRect.value() : [self convertRect:fullViewRect toView:_contentView.get()];
1726
1727     UIEdgeInsets computedContentInsetUnadjustedForKeyboard = [self _computedContentInset];
1728     if (!_haveSetObscuredInsets)
1729         computedContentInsetUnadjustedForKeyboard.bottom -= _totalScrollViewBottomInsetAdjustmentForKeyboard;
1730
1731     CGRect unobscuredRect = UIEdgeInsetsInsetRect(fullViewRect, computedContentInsetUnadjustedForKeyboard);
1732     CGRect unobscuredRectInContentCoordinates = _frozenUnobscuredContentRect ? _frozenUnobscuredContentRect.value() : [self convertRect:unobscuredRect toView:_contentView.get()];
1733
1734     CGFloat scaleFactor = contentZoomScale(self);
1735
1736     BOOL isStableState = !(_isChangingObscuredInsetsInteractively || [_scrollView isDragging] || [_scrollView isDecelerating] || [_scrollView isZooming] || [_scrollView _isAnimatingZoom] || [_scrollView _isScrollingToTop] || [self _scrollViewIsRubberBanding]);
1737
1738     // FIXME: this can be made static after we stop supporting iOS 8.x.
1739     if (isStableState && [_scrollView respondsToSelector:@selector(_isInterruptingDeceleration)])
1740         isStableState = ![_scrollView performSelector:@selector(_isInterruptingDeceleration)];
1741
1742 #if ENABLE(CSS_SCROLL_SNAP) && ENABLE(ASYNC_SCROLLING)
1743     if (isStableState) {
1744         WebKit::RemoteScrollingCoordinatorProxy* coordinator = _page->scrollingCoordinatorProxy();
1745         if (coordinator && coordinator->hasActiveSnapPoint()) {
1746             CGRect fullViewRect = self.bounds;
1747             CGRect unobscuredRect = UIEdgeInsetsInsetRect(fullViewRect, computedContentInsetUnadjustedForKeyboard);
1748             
1749             CGPoint currentPoint = [_scrollView contentOffset];
1750             CGPoint activePoint = coordinator->nearestActiveContentInsetAdjustedSnapPoint(unobscuredRect.origin.y, currentPoint);
1751
1752             if (!CGPointEqualToPoint(activePoint, currentPoint)) {
1753                 RetainPtr<WKScrollView> strongScrollView = _scrollView;
1754                 dispatch_async(dispatch_get_main_queue(), [strongScrollView, activePoint] {
1755                     [strongScrollView setContentOffset:activePoint animated:NO];
1756                 });
1757             }
1758         }
1759     }
1760 #endif
1761     
1762     [_contentView didUpdateVisibleRect:visibleRectInContentCoordinates
1763         unobscuredRect:unobscuredRectInContentCoordinates
1764         unobscuredRectInScrollViewCoordinates:unobscuredRect
1765         scale:scaleFactor minimumScale:[_scrollView minimumZoomScale]
1766         inStableState:isStableState isChangingObscuredInsetsInteractively:_isChangingObscuredInsetsInteractively];
1767 }
1768
1769 - (void)_didFinishLoadForMainFrame
1770 {
1771     if (_gestureController)
1772         _gestureController->didFinishLoadForMainFrame();
1773 }
1774
1775 - (void)_didFailLoadForMainFrame
1776 {
1777     if (_gestureController)
1778         _gestureController->didFailLoadForMainFrame();
1779 }
1780
1781 - (void)_didSameDocumentNavigationForMainFrame:(WebKit::SameDocumentNavigationType)navigationType
1782 {
1783     [_customContentView web_didSameDocumentNavigation:toAPI(navigationType)];
1784
1785     if (_gestureController)
1786         _gestureController->didSameDocumentNavigationForMainFrame(navigationType);
1787 }
1788
1789 - (void)_keyboardChangedWithInfo:(NSDictionary *)keyboardInfo adjustScrollView:(BOOL)adjustScrollView
1790 {
1791     NSValue *endFrameValue = [keyboardInfo objectForKey:UIKeyboardFrameEndUserInfoKey];
1792     if (!endFrameValue)
1793         return;
1794
1795     // The keyboard rect is always in screen coordinates. In the view services case the window does not
1796     // have the interface orientation rotation transformation; its host does. So, it makes no sense to
1797     // clip the keyboard rect against its screen.
1798     if ([[self window] _isHostedInAnotherProcess])
1799         _inputViewBounds = [self.window convertRect:[endFrameValue CGRectValue] fromWindow:nil];
1800     else
1801         _inputViewBounds = [self.window convertRect:CGRectIntersection([endFrameValue CGRectValue], self.window.screen.bounds) fromWindow:nil];
1802
1803     if (adjustScrollView) {
1804         CGFloat bottomInsetBeforeAdjustment = [_scrollView contentInset].bottom;
1805         TemporaryChange<BOOL> insetAdjustmentGuard(_currentlyAdjustingScrollViewInsetsForKeyboard, YES);
1806         [_scrollView _adjustForAutomaticKeyboardInfo:keyboardInfo animated:YES lastAdjustment:&_lastAdjustmentForScroller];
1807         CGFloat bottomInsetAfterAdjustment = [_scrollView contentInset].bottom;
1808         if (bottomInsetBeforeAdjustment != bottomInsetAfterAdjustment)
1809             _totalScrollViewBottomInsetAdjustmentForKeyboard += bottomInsetAfterAdjustment - bottomInsetBeforeAdjustment;
1810     }
1811
1812     [self _updateVisibleContentRects];
1813 }
1814
1815 - (BOOL)_shouldUpdateKeyboardWithInfo:(NSDictionary *)keyboardInfo
1816 {
1817     if ([_contentView isAssistingNode])
1818         return YES;
1819
1820     NSNumber *isLocalKeyboard = [keyboardInfo valueForKey:UIKeyboardIsLocalUserInfoKey];
1821     return isLocalKeyboard && !isLocalKeyboard.boolValue;
1822 }
1823
1824 - (void)_keyboardWillChangeFrame:(NSNotification *)notification
1825 {
1826     if ([self _shouldUpdateKeyboardWithInfo:notification.userInfo])
1827         [self _keyboardChangedWithInfo:notification.userInfo adjustScrollView:YES];
1828 }
1829
1830 - (void)_keyboardDidChangeFrame:(NSNotification *)notification
1831 {
1832     [self _keyboardChangedWithInfo:notification.userInfo adjustScrollView:NO];
1833 }
1834
1835 - (void)_keyboardWillShow:(NSNotification *)notification
1836 {
1837     if ([self _shouldUpdateKeyboardWithInfo:notification.userInfo])
1838         [self _keyboardChangedWithInfo:notification.userInfo adjustScrollView:YES];
1839 }
1840
1841 - (void)_keyboardWillHide:(NSNotification *)notification
1842 {
1843     // Ignore keyboard will hide notifications sent during rotation. They're just there for
1844     // backwards compatibility reasons and processing the will hide notification would
1845     // temporarily screw up the the unobscured view area.
1846     if ([[UIPeripheralHost sharedInstance] rotationState])
1847         return;
1848
1849     [self _keyboardChangedWithInfo:notification.userInfo adjustScrollView:YES];
1850 }
1851
1852 - (void)_windowDidRotate:(NSNotification *)notification
1853 {
1854     if (!_overridesInterfaceOrientation)
1855         _page->setDeviceOrientation(deviceOrientation());
1856 }
1857
1858 - (void)_contentSizeCategoryDidChange:(NSNotification *)notification
1859 {
1860     _page->contentSizeCategoryDidChange([self _contentSizeCategory]);
1861 }
1862
1863 - (NSString *)_contentSizeCategory
1864 {
1865     return [[UIApplication sharedApplication] preferredContentSizeCategory];
1866 }
1867
1868 - (void)setAllowsBackForwardNavigationGestures:(BOOL)allowsBackForwardNavigationGestures
1869 {
1870     if (_allowsBackForwardNavigationGestures == allowsBackForwardNavigationGestures)
1871         return;
1872
1873     _allowsBackForwardNavigationGestures = allowsBackForwardNavigationGestures;
1874
1875     if (allowsBackForwardNavigationGestures) {
1876         if (!_gestureController) {
1877             _gestureController = std::make_unique<WebKit::ViewGestureController>(*_page);
1878             _gestureController->installSwipeHandler(self, [self scrollView]);
1879             _gestureController->setAlternateBackForwardListSourceView([_configuration _alternateWebViewForNavigationGestures]);
1880         }
1881     } else
1882         _gestureController = nullptr;
1883
1884     _page->setShouldRecordNavigationSnapshots(allowsBackForwardNavigationGestures);
1885 }
1886
1887 - (BOOL)allowsBackForwardNavigationGestures
1888 {
1889     return _allowsBackForwardNavigationGestures;
1890 }
1891
1892 - (void)_navigationGestureDidBegin
1893 {
1894     // During a back/forward swipe, there's a view interposed between this view and the content view that has
1895     // an offset and animation on it, which results in computing incorrect rectangles. Work around by using
1896     // frozen rects during swipes.
1897     CGRect fullViewRect = self.bounds;
1898     CGRect unobscuredRect = UIEdgeInsetsInsetRect(fullViewRect, [self _computedContentInset]);
1899
1900     _frozenVisibleContentRect = [self convertRect:fullViewRect toView:_contentView.get()];
1901     _frozenUnobscuredContentRect = [self convertRect:unobscuredRect toView:_contentView.get()];
1902 }
1903
1904 - (void)_navigationGestureDidEnd
1905 {
1906     _frozenVisibleContentRect = Nullopt;
1907     _frozenUnobscuredContentRect = Nullopt;
1908 }
1909
1910 #endif // PLATFORM(IOS)
1911
1912 #pragma mark OS X-specific methods
1913
1914 #if PLATFORM(MAC)
1915
1916 - (BOOL)acceptsFirstResponder
1917 {
1918     return _impl->acceptsFirstResponder();
1919 }
1920
1921 - (BOOL)becomeFirstResponder
1922 {
1923     return _impl->becomeFirstResponder();
1924 }
1925
1926 - (BOOL)resignFirstResponder
1927 {
1928     return _impl->resignFirstResponder();
1929 }
1930
1931 - (void)viewWillStartLiveResize
1932 {
1933     _impl->viewWillStartLiveResize();
1934 }
1935
1936 - (void)viewDidEndLiveResize
1937 {
1938     _impl->viewDidEndLiveResize();
1939 }
1940
1941 - (BOOL)isFlipped
1942 {
1943     return YES;
1944 }
1945
1946 - (NSSize)intrinsicContentSize
1947 {
1948     return NSSizeFromCGSize(_impl->intrinsicContentSize());
1949 }
1950
1951 - (void)prepareContentInRect:(NSRect)rect
1952 {
1953     _impl->prepareContentInRect(NSRectToCGRect(rect));
1954 }
1955
1956 - (void)setFrameSize:(NSSize)size
1957 {
1958     [super setFrameSize:size];
1959     _impl->setFrameSize(NSSizeToCGSize(size));
1960 }
1961
1962 - (void)renewGState
1963 {
1964     _impl->renewGState();
1965     [super renewGState];
1966 }
1967
1968 #define WEBCORE_COMMAND(command) - (void)command:(id)sender { _impl->executeEditCommandForSelector(_cmd); }
1969
1970 WEBCORE_COMMAND(alignCenter)
1971 WEBCORE_COMMAND(alignJustified)
1972 WEBCORE_COMMAND(alignLeft)
1973 WEBCORE_COMMAND(alignRight)
1974 WEBCORE_COMMAND(copy)
1975 WEBCORE_COMMAND(cut)
1976 WEBCORE_COMMAND(delete)
1977 WEBCORE_COMMAND(deleteBackward)
1978 WEBCORE_COMMAND(deleteBackwardByDecomposingPreviousCharacter)
1979 WEBCORE_COMMAND(deleteForward)
1980 WEBCORE_COMMAND(deleteToBeginningOfLine)
1981 WEBCORE_COMMAND(deleteToBeginningOfParagraph)
1982 WEBCORE_COMMAND(deleteToEndOfLine)
1983 WEBCORE_COMMAND(deleteToEndOfParagraph)
1984 WEBCORE_COMMAND(deleteToMark)
1985 WEBCORE_COMMAND(deleteWordBackward)
1986 WEBCORE_COMMAND(deleteWordForward)
1987 WEBCORE_COMMAND(ignoreSpelling)
1988 WEBCORE_COMMAND(indent)
1989 WEBCORE_COMMAND(insertBacktab)
1990 WEBCORE_COMMAND(insertLineBreak)
1991 WEBCORE_COMMAND(insertNewline)
1992 WEBCORE_COMMAND(insertNewlineIgnoringFieldEditor)
1993 WEBCORE_COMMAND(insertParagraphSeparator)
1994 WEBCORE_COMMAND(insertTab)
1995 WEBCORE_COMMAND(insertTabIgnoringFieldEditor)
1996 WEBCORE_COMMAND(makeTextWritingDirectionLeftToRight)
1997 WEBCORE_COMMAND(makeTextWritingDirectionNatural)
1998 WEBCORE_COMMAND(makeTextWritingDirectionRightToLeft)
1999 WEBCORE_COMMAND(moveBackward)
2000 WEBCORE_COMMAND(moveBackwardAndModifySelection)
2001 WEBCORE_COMMAND(moveDown)
2002 WEBCORE_COMMAND(moveDownAndModifySelection)
2003 WEBCORE_COMMAND(moveForward)
2004 WEBCORE_COMMAND(moveForwardAndModifySelection)
2005 WEBCORE_COMMAND(moveLeft)
2006 WEBCORE_COMMAND(moveLeftAndModifySelection)
2007 WEBCORE_COMMAND(moveParagraphBackwardAndModifySelection)
2008 WEBCORE_COMMAND(moveParagraphForwardAndModifySelection)
2009 WEBCORE_COMMAND(moveRight)
2010 WEBCORE_COMMAND(moveRightAndModifySelection)
2011 WEBCORE_COMMAND(moveToBeginningOfDocument)
2012 WEBCORE_COMMAND(moveToBeginningOfDocumentAndModifySelection)
2013 WEBCORE_COMMAND(moveToBeginningOfLine)
2014 WEBCORE_COMMAND(moveToBeginningOfLineAndModifySelection)
2015 WEBCORE_COMMAND(moveToBeginningOfParagraph)
2016 WEBCORE_COMMAND(moveToBeginningOfParagraphAndModifySelection)
2017 WEBCORE_COMMAND(moveToBeginningOfSentence)
2018 WEBCORE_COMMAND(moveToBeginningOfSentenceAndModifySelection)
2019 WEBCORE_COMMAND(moveToEndOfDocument)
2020 WEBCORE_COMMAND(moveToEndOfDocumentAndModifySelection)
2021 WEBCORE_COMMAND(moveToEndOfLine)
2022 WEBCORE_COMMAND(moveToEndOfLineAndModifySelection)
2023 WEBCORE_COMMAND(moveToEndOfParagraph)
2024 WEBCORE_COMMAND(moveToEndOfParagraphAndModifySelection)
2025 WEBCORE_COMMAND(moveToEndOfSentence)
2026 WEBCORE_COMMAND(moveToEndOfSentenceAndModifySelection)
2027 WEBCORE_COMMAND(moveToLeftEndOfLine)
2028 WEBCORE_COMMAND(moveToLeftEndOfLineAndModifySelection)
2029 WEBCORE_COMMAND(moveToRightEndOfLine)
2030 WEBCORE_COMMAND(moveToRightEndOfLineAndModifySelection)
2031 WEBCORE_COMMAND(moveUp)
2032 WEBCORE_COMMAND(moveUpAndModifySelection)
2033 WEBCORE_COMMAND(moveWordBackward)
2034 WEBCORE_COMMAND(moveWordBackwardAndModifySelection)
2035 WEBCORE_COMMAND(moveWordForward)
2036 WEBCORE_COMMAND(moveWordForwardAndModifySelection)
2037 WEBCORE_COMMAND(moveWordLeft)
2038 WEBCORE_COMMAND(moveWordLeftAndModifySelection)
2039 WEBCORE_COMMAND(moveWordRight)
2040 WEBCORE_COMMAND(moveWordRightAndModifySelection)
2041 WEBCORE_COMMAND(outdent)
2042 WEBCORE_COMMAND(pageDown)
2043 WEBCORE_COMMAND(pageDownAndModifySelection)
2044 WEBCORE_COMMAND(pageUp)
2045 WEBCORE_COMMAND(pageUpAndModifySelection)
2046 WEBCORE_COMMAND(paste)
2047 WEBCORE_COMMAND(pasteAsPlainText)
2048 WEBCORE_COMMAND(scrollPageDown)
2049 WEBCORE_COMMAND(scrollPageUp)
2050 WEBCORE_COMMAND(scrollLineDown)
2051 WEBCORE_COMMAND(scrollLineUp)
2052 WEBCORE_COMMAND(scrollToBeginningOfDocument)
2053 WEBCORE_COMMAND(scrollToEndOfDocument)
2054 WEBCORE_COMMAND(selectAll)
2055 WEBCORE_COMMAND(selectLine)
2056 WEBCORE_COMMAND(selectParagraph)
2057 WEBCORE_COMMAND(selectSentence)
2058 WEBCORE_COMMAND(selectToMark)
2059 WEBCORE_COMMAND(selectWord)
2060 WEBCORE_COMMAND(setMark)
2061 WEBCORE_COMMAND(subscript)
2062 WEBCORE_COMMAND(superscript)
2063 WEBCORE_COMMAND(swapWithMark)
2064 WEBCORE_COMMAND(takeFindStringFromSelection)
2065 WEBCORE_COMMAND(transpose)
2066 WEBCORE_COMMAND(underline)
2067 WEBCORE_COMMAND(unscript)
2068 WEBCORE_COMMAND(yank)
2069 WEBCORE_COMMAND(yankAndSelect)
2070
2071 #undef WEBCORE_COMMAND
2072
2073 - (BOOL)writeSelectionToPasteboard:(NSPasteboard *)pasteboard types:(NSArray *)types
2074 {
2075     return _impl->writeSelectionToPasteboard(pasteboard, types);
2076 }
2077
2078 - (void)centerSelectionInVisibleArea:(id)sender
2079 {
2080     _impl->centerSelectionInVisibleArea();
2081 }
2082
2083 - (id)validRequestorForSendType:(NSString *)sendType returnType:(NSString *)returnType
2084 {
2085     return _impl->validRequestorForSendAndReturnTypes(sendType, returnType);
2086 }
2087
2088 - (BOOL)readSelectionFromPasteboard:(NSPasteboard *)pasteboard
2089 {
2090     return _impl->readSelectionFromPasteboard(pasteboard);
2091 }
2092
2093 - (void)changeFont:(id)sender
2094 {
2095     _impl->changeFontFromFontPanel();
2096 }
2097
2098 - (IBAction)startSpeaking:(id)sender
2099 {
2100     _impl->startSpeaking();
2101 }
2102
2103 - (IBAction)stopSpeaking:(id)sender
2104 {
2105     _impl->stopSpeaking(sender);
2106 }
2107
2108 - (IBAction)showGuessPanel:(id)sender
2109 {
2110     _impl->showGuessPanel(sender);
2111 }
2112
2113 - (IBAction)checkSpelling:(id)sender
2114 {
2115     _impl->checkSpelling();
2116 }
2117
2118 - (void)changeSpelling:(id)sender
2119 {
2120     _impl->changeSpelling(sender);
2121 }
2122
2123 - (IBAction)toggleContinuousSpellChecking:(id)sender
2124 {
2125     _impl->toggleContinuousSpellChecking();
2126 }
2127
2128 - (BOOL)isGrammarCheckingEnabled
2129 {
2130     return _impl->isGrammarCheckingEnabled();
2131 }
2132
2133 - (void)setGrammarCheckingEnabled:(BOOL)flag
2134 {
2135     _impl->setGrammarCheckingEnabled(flag);
2136 }
2137
2138 - (IBAction)toggleGrammarChecking:(id)sender
2139 {
2140     _impl->toggleGrammarChecking();
2141 }
2142
2143 - (IBAction)toggleAutomaticSpellingCorrection:(id)sender
2144 {
2145     _impl->toggleAutomaticSpellingCorrection();
2146 }
2147
2148 - (void)orderFrontSubstitutionsPanel:(id)sender
2149 {
2150     _impl->orderFrontSubstitutionsPanel(sender);
2151 }
2152
2153 - (IBAction)toggleSmartInsertDelete:(id)sender
2154 {
2155     _impl->toggleSmartInsertDelete();
2156 }
2157
2158 - (BOOL)isAutomaticQuoteSubstitutionEnabled
2159 {
2160     return _impl->isAutomaticQuoteSubstitutionEnabled();
2161 }
2162
2163 - (void)setAutomaticQuoteSubstitutionEnabled:(BOOL)flag
2164 {
2165     _impl->setAutomaticQuoteSubstitutionEnabled(flag);
2166 }
2167
2168 - (void)toggleAutomaticQuoteSubstitution:(id)sender
2169 {
2170     _impl->toggleAutomaticQuoteSubstitution();
2171 }
2172
2173 - (BOOL)isAutomaticDashSubstitutionEnabled
2174 {
2175     return _impl->isAutomaticDashSubstitutionEnabled();
2176 }
2177
2178 - (void)setAutomaticDashSubstitutionEnabled:(BOOL)flag
2179 {
2180     _impl->setAutomaticDashSubstitutionEnabled(flag);
2181 }
2182
2183 - (void)toggleAutomaticDashSubstitution:(id)sender
2184 {
2185     _impl->toggleAutomaticDashSubstitution();
2186 }
2187
2188 - (BOOL)isAutomaticLinkDetectionEnabled
2189 {
2190     return _impl->isAutomaticLinkDetectionEnabled();
2191 }
2192
2193 - (void)setAutomaticLinkDetectionEnabled:(BOOL)flag
2194 {
2195     _impl->setAutomaticLinkDetectionEnabled(flag);
2196 }
2197
2198 - (void)toggleAutomaticLinkDetection:(id)sender
2199 {
2200     _impl->toggleAutomaticLinkDetection();
2201 }
2202
2203 - (BOOL)isAutomaticTextReplacementEnabled
2204 {
2205     return _impl->isAutomaticTextReplacementEnabled();
2206 }
2207
2208 - (void)setAutomaticTextReplacementEnabled:(BOOL)flag
2209 {
2210     _impl->setAutomaticTextReplacementEnabled(flag);
2211 }
2212
2213 - (void)toggleAutomaticTextReplacement:(id)sender
2214 {
2215     _impl->toggleAutomaticTextReplacement();
2216 }
2217
2218 - (void)uppercaseWord:(id)sender
2219 {
2220     _impl->uppercaseWord();
2221 }
2222
2223 - (void)lowercaseWord:(id)sender
2224 {
2225     _impl->lowercaseWord();
2226 }
2227
2228 - (void)capitalizeWord:(id)sender
2229 {
2230     _impl->capitalizeWord();
2231 }
2232
2233 - (BOOL)_wantsKeyDownForEvent:(NSEvent *)event
2234 {
2235     return _impl->wantsKeyDownForEvent(event);
2236 }
2237
2238 - (void)scrollWheel:(NSEvent *)event
2239 {
2240     _impl->scrollWheel(event);
2241 }
2242
2243 - (void)swipeWithEvent:(NSEvent *)event
2244 {
2245     _impl->swipeWithEvent(event);
2246 }
2247
2248 - (void)mouseMoved:(NSEvent *)event
2249 {
2250     _impl->mouseMoved(event);
2251 }
2252
2253 - (void)mouseDown:(NSEvent *)event
2254 {
2255     _impl->mouseDown(event);
2256 }
2257
2258 - (void)mouseUp:(NSEvent *)event
2259 {
2260     _impl->mouseUp(event);
2261 }
2262
2263 - (void)mouseDragged:(NSEvent *)event
2264 {
2265     _impl->mouseDragged(event);
2266 }
2267
2268 - (void)mouseEntered:(NSEvent *)event
2269 {
2270     _impl->mouseEntered(event);
2271 }
2272
2273 - (void)mouseExited:(NSEvent *)event
2274 {
2275     _impl->mouseExited(event);
2276 }
2277
2278 - (void)otherMouseDown:(NSEvent *)event
2279 {
2280     _impl->otherMouseDown(event);
2281 }
2282
2283 - (void)otherMouseDragged:(NSEvent *)event
2284 {
2285     _impl->otherMouseDragged(event);
2286 }
2287
2288 - (void)otherMouseUp:(NSEvent *)event
2289 {
2290     _impl->otherMouseUp(event);
2291 }
2292
2293 - (void)rightMouseDown:(NSEvent *)event
2294 {
2295     _impl->rightMouseDown(event);
2296 }
2297
2298 - (void)rightMouseDragged:(NSEvent *)event
2299 {
2300     _impl->rightMouseDragged(event);
2301 }
2302
2303 - (void)rightMouseUp:(NSEvent *)event
2304 {
2305     _impl->rightMouseUp(event);
2306 }
2307
2308 - (void)pressureChangeWithEvent:(NSEvent *)event
2309 {
2310     _impl->pressureChangeWithEvent(event);
2311 }
2312
2313 - (BOOL)acceptsFirstMouse:(NSEvent *)event
2314 {
2315     return _impl->acceptsFirstMouse(event);
2316 }
2317
2318 - (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent *)event
2319 {
2320     return _impl->shouldDelayWindowOrderingForEvent(event);
2321 }
2322
2323 - (void)doCommandBySelector:(SEL)selector
2324 {
2325     _impl->doCommandBySelector(selector);
2326 }
2327
2328 - (void)insertText:(id)string
2329 {
2330     _impl->insertText(string);
2331 }
2332
2333 - (void)insertText:(id)string replacementRange:(NSRange)replacementRange
2334 {
2335     _impl->insertText(string, replacementRange);
2336 }
2337
2338 - (NSTextInputContext *)inputContext
2339 {
2340     return _impl->inputContext();
2341 }
2342
2343 - (BOOL)performKeyEquivalent:(NSEvent *)event
2344 {
2345     return _impl->performKeyEquivalent(event);
2346 }
2347
2348 - (void)keyUp:(NSEvent *)theEvent
2349 {
2350     _impl->keyUp(theEvent);
2351 }
2352
2353 - (void)keyDown:(NSEvent *)theEvent
2354 {
2355     _impl->keyDown(theEvent);
2356 }
2357
2358 - (void)flagsChanged:(NSEvent *)theEvent
2359 {
2360     _impl->flagsChanged(theEvent);
2361 }
2362
2363 - (void)setMarkedText:(id)string selectedRange:(NSRange)newSelectedRange replacementRange:(NSRange)replacementRange
2364 {
2365     _impl->setMarkedText(string, newSelectedRange, replacementRange);
2366 }
2367
2368 - (void)unmarkText
2369 {
2370     _impl->unmarkText();
2371 }
2372
2373 - (NSRange)selectedRange
2374 {
2375     return _impl->selectedRange();
2376 }
2377
2378 - (BOOL)hasMarkedText
2379 {
2380     return _impl->hasMarkedText();
2381 }
2382
2383 - (NSRange)markedRange
2384 {
2385     return _impl->markedRange();
2386 }
2387
2388 - (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)nsRange actualRange:(NSRangePointer)actualRange
2389 {
2390     return _impl->attributedSubstringForProposedRange(nsRange, actualRange);
2391 }
2392
2393 - (NSUInteger)characterIndexForPoint:(NSPoint)thePoint
2394 {
2395     return _impl->characterIndexForPoint(thePoint);
2396 }
2397
2398 - (NSRect)firstRectForCharacterRange:(NSRange)theRange actualRange:(NSRangePointer)actualRange
2399 {
2400     return _impl->firstRectForCharacterRange(theRange, actualRange);
2401 }
2402
2403 #if USE(ASYNC_NSTEXTINPUTCLIENT)
2404
2405 - (void)selectedRangeWithCompletionHandler:(void(^)(NSRange selectedRange))completionHandlerPtr
2406 {
2407     _impl->selectedRangeWithCompletionHandler(completionHandlerPtr);
2408 }
2409
2410 - (void)markedRangeWithCompletionHandler:(void(^)(NSRange markedRange))completionHandlerPtr
2411 {
2412     _impl->markedRangeWithCompletionHandler(completionHandlerPtr);
2413 }
2414
2415 - (void)hasMarkedTextWithCompletionHandler:(void(^)(BOOL hasMarkedText))completionHandlerPtr
2416 {
2417     _impl->hasMarkedTextWithCompletionHandler(completionHandlerPtr);
2418 }
2419
2420 - (void)attributedSubstringForProposedRange:(NSRange)nsRange completionHandler:(void(^)(NSAttributedString *attrString, NSRange actualRange))completionHandlerPtr
2421 {
2422     _impl->attributedSubstringForProposedRange(nsRange, completionHandlerPtr);
2423 }
2424
2425 - (void)firstRectForCharacterRange:(NSRange)theRange completionHandler:(void(^)(NSRect firstRect, NSRange actualRange))completionHandlerPtr
2426 {
2427     _impl->firstRectForCharacterRange(theRange, completionHandlerPtr);
2428 }
2429
2430 - (void)characterIndexForPoint:(NSPoint)thePoint completionHandler:(void(^)(NSUInteger))completionHandlerPtr
2431 {
2432     _impl->characterIndexForPoint(thePoint, completionHandlerPtr);
2433 }
2434
2435 #endif // USE(ASYNC_NSTEXTINPUTCLIENT)
2436
2437 - (NSArray *)validAttributesForMarkedText
2438 {
2439     return _impl->validAttributesForMarkedText();
2440 }
2441
2442 #if ENABLE(DRAG_SUPPORT)
2443 - (void)draggedImage:(NSImage *)image endedAt:(NSPoint)endPoint operation:(NSDragOperation)operation
2444 {
2445     _impl->draggedImage(image, NSPointToCGPoint(endPoint), operation);
2446 }
2447
2448 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)draggingInfo
2449 {
2450     return _impl->draggingEntered(draggingInfo);
2451 }
2452
2453 - (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)draggingInfo
2454 {
2455     return _impl->draggingUpdated(draggingInfo);
2456 }
2457
2458 - (void)draggingExited:(id <NSDraggingInfo>)draggingInfo
2459 {
2460     _impl->draggingExited(draggingInfo);
2461 }
2462
2463 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)draggingInfo
2464 {
2465     return _impl->prepareForDragOperation(draggingInfo);
2466 }
2467
2468 - (BOOL)performDragOperation:(id <NSDraggingInfo>)draggingInfo
2469 {
2470     return _impl->performDragOperation(draggingInfo);
2471 }
2472
2473 - (NSView *)_hitTest:(NSPoint *)point dragTypes:(NSSet *)types
2474 {
2475     return _impl->hitTestForDragTypes(NSPointToCGPoint(*point), types);
2476 }
2477 #endif // ENABLE(DRAG_SUPPORT)
2478
2479 - (BOOL)_windowResizeMouseLocationIsInVisibleScrollerThumb:(NSPoint)point
2480 {
2481     return _impl->windowResizeMouseLocationIsInVisibleScrollerThumb(NSPointToCGPoint(point));
2482 }
2483
2484 - (void)viewWillMoveToWindow:(NSWindow *)window
2485 {
2486     _impl->viewWillMoveToWindow(window);
2487 }
2488
2489 - (void)viewDidMoveToWindow
2490 {
2491     _impl->viewDidMoveToWindow();
2492 }
2493
2494 - (void)drawRect:(NSRect)rect
2495 {
2496     _impl->drawRect(NSRectToCGRect(rect));
2497 }
2498
2499 - (BOOL)isOpaque
2500 {
2501     return _impl->isOpaque();
2502 }
2503
2504 - (BOOL)mouseDownCanMoveWindow
2505 {
2506     return WebKit::WebViewImpl::mouseDownCanMoveWindow();
2507 }
2508
2509 - (void)viewDidHide
2510 {
2511     _impl->viewDidHide();
2512 }
2513
2514 - (void)viewDidUnhide
2515 {
2516     _impl->viewDidUnhide();
2517 }
2518
2519 - (void)viewDidChangeBackingProperties
2520 {
2521     _impl->viewDidChangeBackingProperties();
2522 }
2523
2524 - (void)_activeSpaceDidChange:(NSNotification *)notification
2525 {
2526     _impl->activeSpaceDidChange();
2527 }
2528
2529 - (id)accessibilityFocusedUIElement
2530 {
2531     return _impl->accessibilityFocusedUIElement();
2532 }
2533
2534 - (BOOL)accessibilityIsIgnored
2535 {
2536     return _impl->accessibilityIsIgnored();
2537 }
2538
2539 - (id)accessibilityHitTest:(NSPoint)point
2540 {
2541     return _impl->accessibilityHitTest(NSPointToCGPoint(point));
2542 }
2543
2544 - (id)accessibilityAttributeValue:(NSString *)attribute
2545 {
2546     return _impl->accessibilityAttributeValue(attribute);
2547 }
2548
2549 - (NSView *)hitTest:(NSPoint)point
2550 {
2551     if (!_impl)
2552         return [super hitTest:point];
2553     return _impl->hitTest(NSPointToCGPoint(point));
2554 }
2555
2556 - (NSInteger)conversationIdentifier
2557 {
2558     return (NSInteger)self;
2559 }
2560
2561 - (void)quickLookWithEvent:(NSEvent *)event
2562 {
2563     _impl->quickLookWithEvent(event);
2564 }
2565
2566 - (NSTrackingRectTag)addTrackingRect:(NSRect)rect owner:(id)owner userData:(void *)data assumeInside:(BOOL)assumeInside
2567 {
2568     return _impl->addTrackingRect(NSRectToCGRect(rect), owner, data, assumeInside);
2569 }
2570
2571 - (NSTrackingRectTag)_addTrackingRect:(NSRect)rect owner:(id)owner userData:(void *)data assumeInside:(BOOL)assumeInside useTrackingNum:(int)tag
2572 {
2573     return _impl->addTrackingRectWithTrackingNum(NSRectToCGRect(rect), owner, data, assumeInside, tag);
2574 }
2575
2576 - (void)_addTrackingRects:(NSRect *)rects owner:(id)owner userDataList:(void **)userDataList assumeInsideList:(BOOL *)assumeInsideList trackingNums:(NSTrackingRectTag *)trackingNums count:(int)count
2577 {
2578     CGRect *cgRects = (CGRect *)calloc(1, sizeof(CGRect));
2579     for (int i = 0; i < count; i++)
2580         cgRects[i] = NSRectToCGRect(rects[i]);
2581     _impl->addTrackingRectsWithTrackingNums(cgRects, owner, userDataList, assumeInsideList, trackingNums, count);
2582     free(cgRects);
2583 }
2584
2585 - (void)removeTrackingRect:(NSTrackingRectTag)tag
2586 {
2587     if (!_impl)
2588         return;
2589     _impl->removeTrackingRect(tag);
2590 }
2591
2592 - (void)_removeTrackingRects:(NSTrackingRectTag *)tags count:(int)count
2593 {
2594     if (!_impl)
2595         return;
2596     _impl->removeTrackingRects(tags, count);
2597 }
2598
2599 - (NSString *)view:(NSView *)view stringForToolTip:(NSToolTipTag)tag point:(NSPoint)point userData:(void *)data
2600 {
2601     return _impl->stringForToolTip(tag);
2602 }
2603
2604 - (void)pasteboardChangedOwner:(NSPasteboard *)pasteboard
2605 {
2606     _impl->pasteboardChangedOwner(pasteboard);
2607 }
2608
2609 - (void)pasteboard:(NSPasteboard *)pasteboard provideDataForType:(NSString *)type
2610 {
2611     _impl->provideDataForPasteboard(pasteboard, type);
2612 }
2613
2614 - (NSArray *)namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination
2615 {
2616     return _impl->namesOfPromisedFilesDroppedAtDestination(dropDestination);
2617 }
2618
2619 - (BOOL)wantsUpdateLayer
2620 {
2621     return WebKit::WebViewImpl::wantsUpdateLayer();
2622 }
2623
2624 - (void)updateLayer
2625 {
2626     _impl->updateLayer();
2627 }
2628
2629 - (void)setAllowsBackForwardNavigationGestures:(BOOL)allowsBackForwardNavigationGestures
2630 {
2631     _impl->setAllowsBackForwardNavigationGestures(allowsBackForwardNavigationGestures);
2632 }
2633
2634 - (BOOL)allowsBackForwardNavigationGestures
2635 {
2636     return _impl->allowsBackForwardNavigationGestures();
2637 }
2638
2639 - (void)smartMagnifyWithEvent:(NSEvent *)event
2640 {
2641     _impl->smartMagnifyWithEvent(event);
2642 }
2643
2644 - (void)setMagnification:(double)magnification centeredAtPoint:(NSPoint)point
2645 {
2646     _impl->setMagnification(magnification, NSPointToCGPoint(point));
2647 }
2648
2649 - (void)setMagnification:(double)magnification
2650 {
2651     _impl->setMagnification(magnification);
2652 }
2653
2654 - (double)magnification
2655 {
2656     return _impl->magnification();
2657 }
2658
2659 - (void)setAllowsMagnification:(BOOL)allowsMagnification
2660 {
2661     _impl->setAllowsMagnification(allowsMagnification);
2662 }
2663
2664 - (BOOL)allowsMagnification
2665 {
2666     return _impl->allowsMagnification();
2667 }
2668
2669 - (void)magnifyWithEvent:(NSEvent *)event
2670 {
2671     _impl->magnifyWithEvent(event);
2672 }
2673
2674 #if ENABLE(MAC_GESTURE_EVENTS)
2675 - (void)rotateWithEvent:(NSEvent *)event
2676 {
2677     _impl->rotateWithEvent(event);
2678 }
2679 #endif
2680
2681 - (WKTextFinderClient *)_ensureTextFinderClient
2682 {
2683     if (!_textFinderClient)
2684         _textFinderClient = adoptNS([[WKTextFinderClient alloc] initWithPage:*_page view:self]);
2685     return _textFinderClient.get();
2686 }
2687
2688 - (void)findMatchesForString:(NSString *)targetString relativeToMatch:(id <NSTextFinderAsynchronousDocumentFindMatch>)relativeMatch findOptions:(NSTextFinderAsynchronousDocumentFindOptions)findOptions maxResults:(NSUInteger)maxResults resultCollector:(void (^)(NSArray *matches, BOOL didWrap))resultCollector
2689 {
2690     [[self _ensureTextFinderClient] findMatchesForString:targetString relativeToMatch:relativeMatch findOptions:findOptions maxResults:maxResults resultCollector:resultCollector];
2691 }
2692
2693 - (NSView *)documentContainerView
2694 {
2695     return self;
2696 }
2697
2698 - (void)getSelectedText:(void (^)(NSString *selectedTextString))completionHandler
2699 {
2700     [[self _ensureTextFinderClient] getSelectedText:completionHandler];
2701 }
2702
2703 - (void)selectFindMatch:(id <NSTextFinderAsynchronousDocumentFindMatch>)findMatch completionHandler:(void (^)(void))completionHandler
2704 {
2705     [[self _ensureTextFinderClient] selectFindMatch:findMatch completionHandler:completionHandler];
2706 }
2707
2708 - (NSTextInputContext *)_web_superInputContext
2709 {
2710     return [super inputContext];
2711 }
2712
2713 - (void)_web_superQuickLookWithEvent:(NSEvent *)event
2714 {
2715     [super quickLookWithEvent:event];
2716 }
2717
2718 - (void)_web_superSwipeWithEvent:(NSEvent *)event
2719 {
2720     [super swipeWithEvent:event];
2721 }
2722
2723 - (void)_web_superMagnifyWithEvent:(NSEvent *)event
2724 {
2725     [super magnifyWithEvent:event];
2726 }
2727
2728 - (void)_web_superSmartMagnifyWithEvent:(NSEvent *)event
2729 {
2730     [super smartMagnifyWithEvent:event];
2731 }
2732
2733 - (void)_web_superRemoveTrackingRect:(NSTrackingRectTag)tag
2734 {
2735     [super removeTrackingRect:tag];
2736 }
2737
2738 - (id)_web_superAccessibilityAttributeValue:(NSString *)attribute
2739 {
2740 #pragma clang diagnostic push
2741 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
2742     return [super accessibilityAttributeValue:attribute];
2743 #pragma clang diagnostic pop
2744 }
2745
2746 - (void)_web_superDoCommandBySelector:(SEL)selector
2747 {
2748     [super doCommandBySelector:selector];
2749 }
2750
2751 - (BOOL)_web_superPerformKeyEquivalent:(NSEvent *)event
2752 {
2753     return [super performKeyEquivalent:event];
2754 }
2755
2756 - (void)_web_superKeyDown:(NSEvent *)event
2757 {
2758     [super keyDown:event];
2759 }
2760
2761 - (NSView *)_web_superHitTest:(NSPoint)point
2762 {
2763     return [super hitTest:point];
2764 }
2765
2766 - (id)_web_immediateActionAnimationControllerForHitTestResultInternal:(API::HitTestResult*)hitTestResult withType:(uint32_t)type userData:(API::Object*)userData
2767 {
2768     return [self _immediateActionAnimationControllerForHitTestResult:wrapper(*hitTestResult) withType:(_WKImmediateActionType)type userData:(id)userData];
2769 }
2770
2771 // We don't expose these various bits of SPI like WKView does,
2772 // so have these internal methods just do the work (or do nothing):
2773 - (void)_web_prepareForImmediateActionAnimation
2774 {
2775 }
2776
2777 - (void)_web_cancelImmediateActionAnimation
2778 {
2779 }
2780
2781 - (void)_web_completeImmediateActionAnimation
2782 {
2783 }
2784
2785 - (void)_web_didChangeContentSize:(NSSize)newSize
2786 {
2787 }
2788
2789 - (void)_web_dismissContentRelativeChildWindows
2790 {
2791     _impl->dismissContentRelativeChildWindowsFromViewOnly();
2792 }
2793
2794 - (void)_web_dismissContentRelativeChildWindowsWithAnimation:(BOOL)withAnimation
2795 {
2796     _impl->dismissContentRelativeChildWindowsWithAnimationFromViewOnly(withAnimation);
2797 }
2798
2799 - (void)_web_gestureEventWasNotHandledByWebCore:(NSEvent *)event
2800 {
2801     _impl->gestureEventWasNotHandledByWebCoreFromViewOnly(event);
2802 }
2803
2804 #endif // PLATFORM(MAC)
2805
2806 @end
2807
2808 @implementation WKWebView (WKPrivate)
2809
2810 - (BOOL)_isEditable
2811 {
2812     return _page->isEditable();
2813 }
2814
2815 - (void)_setEditable:(BOOL)editable
2816 {
2817     _page->setEditable(editable);
2818 #if PLATFORM(MAC)
2819     _impl->startObservingFontPanel();
2820 #endif
2821 }
2822
2823 - (_WKRemoteObjectRegistry *)_remoteObjectRegistry
2824 {
2825 #if PLATFORM(MAC)
2826     return _impl->remoteObjectRegistry();
2827 #else
2828     if (!_remoteObjectRegistry) {
2829         _remoteObjectRegistry = adoptNS([[_WKRemoteObjectRegistry alloc] _initWithMessageSender:*_page]);
2830         _page->process().processPool().addMessageReceiver(Messages::RemoteObjectRegistry::messageReceiverName(), _page->pageID(), [_remoteObjectRegistry remoteObjectRegistry]);
2831     }
2832
2833     return _remoteObjectRegistry.get();
2834 #endif
2835 }
2836
2837 - (WKBrowsingContextHandle *)_handle
2838 {
2839     return [[[WKBrowsingContextHandle alloc] _initWithPageID:_page->pageID()] autorelease];
2840 }
2841
2842 - (_WKRenderingProgressEvents)_observedRenderingProgressEvents
2843 {
2844     return _observedRenderingProgressEvents;
2845 }
2846
2847 - (id <WKHistoryDelegatePrivate>)_historyDelegate
2848 {
2849     return _navigationState->historyDelegate().autorelease();
2850 }
2851
2852 - (void)_setHistoryDelegate:(id <WKHistoryDelegatePrivate>)historyDelegate
2853 {
2854     _page->setHistoryClient(_navigationState->createHistoryClient());
2855     _navigationState->setHistoryDelegate(historyDelegate);
2856 }
2857
2858 - (NSURL *)_unreachableURL
2859 {
2860     return [NSURL _web_URLWithWTFString:_page->pageLoadState().unreachableURL()];
2861 }
2862
2863 - (void)_loadAlternateHTMLString:(NSString *)string baseURL:(NSURL *)baseURL forUnreachableURL:(NSURL *)unreachableURL
2864 {
2865     _page->loadAlternateHTMLString(string, [baseURL _web_originalDataAsWTFString], [unreachableURL _web_originalDataAsWTFString]);
2866 }
2867
2868 - (WKNavigation *)_loadData:(NSData *)data MIMEType:(NSString *)MIMEType characterEncodingName:(NSString *)characterEncodingName baseURL:(NSURL *)baseURL userData:(id)userData
2869 {
2870     auto navigation = _page->loadData(API::Data::createWithoutCopying(data).ptr(), MIMEType, characterEncodingName, baseURL.absoluteString, WebKit::ObjCObjectGraph::create(userData).ptr());
2871     if (!navigation)
2872         return nil;
2873
2874     return [wrapper(*navigation.release().leakRef()) autorelease];
2875 }
2876
2877 - (NSArray *)_certificateChain
2878 {
2879     if (WebKit::WebFrameProxy* mainFrame = _page->mainFrame())
2880         return mainFrame->certificateInfo() ? (NSArray *)mainFrame->certificateInfo()->certificateInfo().certificateChain() : nil;
2881
2882     return nil;
2883 }
2884
2885 - (NSURL *)_committedURL
2886 {
2887     return [NSURL _web_URLWithWTFString:_page->pageLoadState().url()];
2888 }
2889
2890 - (NSString *)_MIMEType
2891 {
2892     if (_page->mainFrame())
2893         return _page->mainFrame()->mimeType();
2894
2895     return nil;
2896 }
2897
2898 - (NSString *)_userAgent
2899 {
2900     return _page->userAgent();
2901 }
2902
2903 - (NSString *)_applicationNameForUserAgent
2904 {
2905     return _page->applicationNameForUserAgent();
2906 }
2907
2908 - (void)_setApplicationNameForUserAgent:(NSString *)applicationNameForUserAgent
2909 {
2910     _page->setApplicationNameForUserAgent(applicationNameForUserAgent);
2911 }
2912
2913 - (NSString *)_customUserAgent
2914 {
2915     return self.customUserAgent;
2916 }
2917
2918 - (void)_setCustomUserAgent:(NSString *)customUserAgent
2919 {
2920     self.customUserAgent = customUserAgent;
2921 }
2922
2923 - (void)_setUserContentExtensionsEnabled:(BOOL)userContentExtensionsEnabled
2924 {
2925     // This is kept for binary compatibility with iOS 9.
2926 }
2927
2928 - (BOOL)_userContentExtensionsEnabled
2929 {
2930     // This is kept for binary compatibility with iOS 9.
2931     return true;
2932 }
2933
2934 - (pid_t)_webProcessIdentifier
2935 {
2936     return _page->isValid() ? _page->processIdentifier() : 0;
2937 }
2938
2939 - (void)_killWebContentProcess
2940 {
2941     if (!_page->isValid())
2942         return;
2943
2944     _page->process().terminate();
2945 }
2946
2947 - (WKNavigation *)_reloadWithoutContentBlockers
2948 {
2949     const bool reloadFromOrigin = false;
2950     const bool contentBlockersEnabled = false;
2951     auto navigation = _page->reload(reloadFromOrigin, contentBlockersEnabled);
2952     if (!navigation)
2953         return nil;
2954     
2955     return [wrapper(*navigation.release().leakRef()) autorelease];
2956 }
2957
2958 - (void)_killWebContentProcessAndResetState
2959 {
2960     _page->terminateProcess();
2961 }
2962
2963 #if PLATFORM(IOS)
2964 static WebCore::FloatSize activeMinimumLayoutSize(WKWebView *webView, const CGRect& bounds)
2965 {
2966     return WebCore::FloatSize(webView->_overridesMinimumLayoutSize ? webView->_minimumLayoutSizeOverride : bounds.size);
2967 }
2968
2969 static WebCore::FloatSize activeMaximumUnobscuredSize(WKWebView *webView, const CGRect& bounds)
2970 {
2971     return WebCore::FloatSize(webView->_overridesMaximumUnobscuredSize ? webView->_maximumUnobscuredSizeOverride : bounds.size);
2972 }
2973
2974 static int32_t activeOrientation(WKWebView *webView)
2975 {
2976     return webView->_overridesInterfaceOrientation ? deviceOrientationForUIInterfaceOrientation(webView->_interfaceOrientationOverride) : webView->_page->deviceOrientation();
2977 }
2978
2979 - (void (^)(void))_retainActiveFocusedState
2980 {
2981     ++_activeFocusedStateRetainCount;
2982
2983     // FIXME: Use something like CompletionHandlerCallChecker to ensure that the returned block is called before it's released.
2984     return [[[self] {
2985         --_activeFocusedStateRetainCount;
2986     } copy] autorelease];
2987 }
2988
2989 - (void)_becomeFirstResponderWithSelectionMovingForward:(BOOL)selectingForward completionHandler:(void (^)(BOOL didBecomeFirstResponder))completionHandler
2990 {
2991     typeof(completionHandler) completionHandlerCopy = nil;
2992     if (completionHandler)
2993         completionHandlerCopy = Block_copy(completionHandler);
2994
2995     [_contentView _becomeFirstResponderWithSelectionMovingForward:selectingForward completionHandler:[completionHandlerCopy](BOOL didBecomeFirstResponder) {
2996         if (!completionHandlerCopy)
2997             return;
2998
2999         completionHandlerCopy(didBecomeFirstResponder);
3000         Block_release(completionHandlerCopy);
3001     }];
3002 }
3003
3004 - (id)_snapshotLayerContentsForBackForwardListItem:(WKBackForwardListItem *)item
3005 {
3006     if (_page->backForwardList().currentItem() == &item._item)
3007         _page->recordNavigationSnapshot(*_page->backForwardList().currentItem());
3008
3009     if (auto* viewSnapshot = item._item.snapshot())
3010         return viewSnapshot->asLayerContents();
3011
3012     return nil;
3013 }
3014
3015 #endif
3016
3017 - (void)_didRelaunchProcess
3018 {
3019 #if PLATFORM(IOS)
3020     CGRect bounds = self.bounds;
3021     WebCore::FloatSize minimalLayoutSize = activeMinimumLayoutSize(self, bounds);
3022     _page->setViewportConfigurationMinimumLayoutSize(minimalLayoutSize);
3023     _page->setMaximumUnobscuredSize(activeMaximumUnobscuredSize(self, bounds));
3024 #endif
3025 }
3026
3027 - (NSData *)_sessionStateData
3028 {
3029     WebKit::SessionState sessionState = _page->sessionState();
3030
3031     // FIXME: This should not use the legacy session state encoder.
3032     return [wrapper(*WebKit::encodeLegacySessionState(sessionState).release().leakRef()) autorelease];
3033 }
3034
3035 - (_WKSessionState *)_sessionState
3036 {
3037     return adoptNS([[_WKSessionState alloc] _initWithSessionState:_page->sessionState()]).autorelease();
3038 }
3039
3040 - (void)_restoreFromSessionStateData:(NSData *)sessionStateData
3041 {
3042     // FIXME: This should not use the legacy session state decoder.
3043     WebKit::SessionState sessionState;
3044     if (!WebKit::decodeLegacySessionState(static_cast<const uint8_t*>(sessionStateData.bytes), sessionStateData.length, sessionState))
3045         return;
3046
3047     _page->restoreFromSessionState(WTF::move(sessionState), true);
3048 }
3049
3050 - (WKNavigation *)_restoreSessionState:(_WKSessionState *)sessionState andNavigate:(BOOL)navigate
3051 {
3052     auto navigation = _page->restoreFromSessionState(sessionState->_sessionState, navigate);
3053     if (!navigation)
3054         return nil;
3055
3056     return [wrapper(*navigation.release().leakRef()) autorelease];
3057 }
3058
3059 - (void)_close
3060 {
3061     _page->close();
3062 }
3063
3064 - (BOOL)_allowsRemoteInspection
3065 {
3066 #if ENABLE(REMOTE_INSPECTOR)
3067     return _page->allowsRemoteInspection();
3068 #else
3069     return NO;
3070 #endif
3071 }
3072
3073 - (void)_setAllowsRemoteInspection:(BOOL)allow
3074 {
3075 #if ENABLE(REMOTE_INSPECTOR)
3076     _page->setAllowsRemoteInspection(allow);
3077 #endif
3078 }
3079
3080 - (NSString *)_remoteInspectionNameOverride
3081 {
3082 #if ENABLE(REMOTE_INSPECTOR)
3083     return _page->remoteInspectionNameOverride();
3084 #else
3085     return nil;
3086 #endif
3087 }
3088
3089 - (void)_setRemoteInspectionNameOverride:(NSString *)name
3090 {
3091 #if ENABLE(REMOTE_INSPECTOR)
3092     _page->setRemoteInspectionNameOverride(name);
3093 #endif
3094 }
3095
3096 - (BOOL)_addsVisitedLinks
3097 {
3098     return _page->addsVisitedLinks();
3099 }
3100
3101 - (void)_setAddsVisitedLinks:(BOOL)addsVisitedLinks
3102 {
3103     _page->setAddsVisitedLinks(addsVisitedLinks);
3104 }
3105
3106 - (BOOL)_networkRequestsInProgress
3107 {
3108     return _page->pageLoadState().networkRequestsInProgress();
3109 }
3110
3111 static inline WebCore::LayoutMilestones layoutMilestones(_WKRenderingProgressEvents events)
3112 {
3113     WebCore::LayoutMilestones milestones = 0;
3114
3115     if (events & _WKRenderingProgressEventFirstLayout)
3116         milestones |= WebCore::DidFirstLayout;
3117
3118     if (events & _WKRenderingProgressEventFirstVisuallyNonEmptyLayout)
3119         milestones |= WebCore::DidFirstVisuallyNonEmptyLayout;
3120
3121     if (events & _WKRenderingProgressEventFirstPaintWithSignificantArea)
3122         milestones |= WebCore::DidHitRelevantRepaintedObjectsAreaThreshold;
3123
3124     if (events & _WKRenderingProgressEventReachedSessionRestorationRenderTreeSizeThreshold)
3125         milestones |= WebCore::ReachedSessionRestorationRenderTreeSizeThreshold;
3126
3127     if (events & _WKRenderingProgressEventFirstLayoutAfterSuppressedIncrementalRendering)
3128         milestones |= WebCore::DidFirstLayoutAfterSuppressedIncrementalRendering;
3129
3130     if (events & _WKRenderingProgressEventFirstPaintAfterSuppressedIncrementalRendering)
3131         milestones |= WebCore::DidFirstPaintAfterSuppressedIncrementalRendering;
3132
3133     return milestones;
3134 }
3135
3136 - (void)_setObservedRenderingProgressEvents:(_WKRenderingProgressEvents)observedRenderingProgressEvents
3137 {
3138     _observedRenderingProgressEvents = observedRenderingProgressEvents;
3139     _page->listenForLayoutMilestones(layoutMilestones(observedRenderingProgressEvents));
3140 }
3141
3142 - (void)_getMainResourceDataWithCompletionHandler:(void (^)(NSData *, NSError *))completionHandler
3143 {
3144     auto handler = adoptNS([completionHandler copy]);
3145
3146     _page->getMainResourceDataOfFrame(_page->mainFrame(), [handler](API::Data* data, WebKit::CallbackBase::Error error) {
3147         void (^completionHandlerBlock)(NSData *, NSError *) = (void (^)(NSData *, NSError *))handler.get();
3148         if (error != WebKit::CallbackBase::Error::None) {
3149             // FIXME: Pipe a proper error in from the WebPageProxy.
3150             RetainPtr<NSError> error = adoptNS([[NSError alloc] init]);
3151             completionHandlerBlock(nil, error.get());
3152         } else
3153             completionHandlerBlock(wrapper(*data), nil);
3154     });
3155 }
3156
3157 - (void)_getWebArchiveDataWithCompletionHandler:(void (^)(NSData *, NSError *))completionHandler
3158 {
3159     auto handler = adoptNS([completionHandler copy]);
3160
3161     _page->getWebArchiveOfFrame(_page->mainFrame(), [handler](API::Data* data, WebKit::CallbackBase::Error error) {
3162         void (^completionHandlerBlock)(NSData *, NSError *) = (void (^)(NSData *, NSError *))handler.get();
3163         if (error != WebKit::CallbackBase::Error::None) {
3164             // FIXME: Pipe a proper error in from the WebPageProxy.
3165             RetainPtr<NSError> error = adoptNS([[NSError alloc] init]);
3166             completionHandlerBlock(nil, error.get());
3167         } else
3168             completionHandlerBlock(wrapper(*data), nil);
3169     });
3170 }
3171
3172 - (_WKPaginationMode)_paginationMode
3173 {
3174     switch (_page->paginationMode()) {
3175     case WebCore::Pagination::Unpaginated:
3176         return _WKPaginationModeUnpaginated;
3177     case WebCore::Pagination::LeftToRightPaginated:
3178         return _WKPaginationModeLeftToRight;
3179     case WebCore::Pagination::RightToLeftPaginated:
3180         return _WKPaginationModeRightToLeft;
3181     case WebCore::Pagination::TopToBottomPaginated:
3182         return _WKPaginationModeTopToBottom;
3183     case WebCore::Pagination::BottomToTopPaginated:
3184         return _WKPaginationModeBottomToTop;
3185     }
3186
3187     ASSERT_NOT_REACHED();
3188     return _WKPaginationModeUnpaginated;
3189 }
3190
3191 - (void)_setPaginationMode:(_WKPaginationMode)paginationMode
3192 {
3193     WebCore::Pagination::Mode mode;
3194     switch (paginationMode) {
3195     case _WKPaginationModeUnpaginated:
3196         mode = WebCore::Pagination::Unpaginated;
3197         break;
3198     case _WKPaginationModeLeftToRight:
3199         mode = WebCore::Pagination::LeftToRightPaginated;
3200         break;
3201     case _WKPaginationModeRightToLeft:
3202         mode = WebCore::Pagination::RightToLeftPaginated;
3203         break;
3204     case _WKPaginationModeTopToBottom:
3205         mode = WebCore::Pagination::TopToBottomPaginated;
3206         break;
3207     case _WKPaginationModeBottomToTop:
3208         mode = WebCore::Pagination::BottomToTopPaginated;
3209         break;
3210     default:
3211         return;
3212     }
3213
3214     _page->setPaginationMode(mode);
3215 }
3216
3217 - (BOOL)_paginationBehavesLikeColumns
3218 {
3219     return _page->paginationBehavesLikeColumns();
3220 }
3221
3222 - (void)_setPaginationBehavesLikeColumns:(BOOL)behavesLikeColumns
3223 {
3224     _page->setPaginationBehavesLikeColumns(behavesLikeColumns);
3225 }
3226
3227 - (CGFloat)_pageLength
3228 {
3229     return _page->pageLength();
3230 }
3231
3232 - (void)_setPageLength:(CGFloat)pageLength
3233 {
3234     _page->setPageLength(pageLength);
3235 }
3236
3237 - (CGFloat)_gapBetweenPages
3238 {
3239     return _page->gapBetweenPages();
3240 }
3241
3242 - (void)_setGapBetweenPages:(CGFloat)gapBetweenPages
3243 {
3244     _page->setGapBetweenPages(gapBetweenPages);
3245 }
3246
3247 - (NSUInteger)_pageCount
3248 {
3249     return _page->pageCount();
3250 }
3251
3252 - (BOOL)_supportsTextZoom
3253 {
3254     return _page->supportsTextZoom();
3255 }
3256
3257 - (double)_textZoomFactor
3258 {
3259     return _page->textZoomFactor();
3260 }
3261
3262 - (void)_setTextZoomFactor:(double)zoomFactor
3263 {
3264     _page->setTextZoomFactor(zoomFactor);
3265 }
3266
3267 - (double)_pageZoomFactor
3268 {
3269     return _page->pageZoomFactor();
3270 }
3271
3272 - (void)_setPageZoomFactor:(double)zoomFactor
3273 {
3274     _page->setPageZoomFactor(zoomFactor);
3275 }
3276
3277 - (id <_WKDiagnosticLoggingDelegate>)_diagnosticLoggingDelegate
3278 {
3279     return [static_cast<WebKit::DiagnosticLoggingClient&>(_page->diagnosticLoggingClient()).delegate().leakRef() autorelease];
3280 }
3281
3282 - (void)_setDiagnosticLoggingDelegate:(id<_WKDiagnosticLoggingDelegate>)diagnosticLoggingDelegate
3283 {
3284     static_cast<WebKit::DiagnosticLoggingClient&>(_page->diagnosticLoggingClient()).setDelegate(diagnosticLoggingDelegate);
3285 }
3286
3287 - (id <_WKFindDelegate>)_findDelegate
3288 {
3289     return [static_cast<WebKit::FindClient&>(_page->findClient()).delegate().leakRef() autorelease];
3290 }
3291
3292 - (void)_setFindDelegate:(id<_WKFindDelegate>)findDelegate
3293 {
3294     static_cast<WebKit::FindClient&>(_page->findClient()).setDelegate(findDelegate);
3295 }
3296
3297 static inline WebKit::FindOptions toFindOptions(_WKFindOptions wkFindOptions)
3298 {
3299     unsigned findOptions = 0;
3300
3301     if (wkFindOptions & _WKFindOptionsCaseInsensitive)
3302         findOptions |= WebKit::FindOptionsCaseInsensitive;
3303     if (wkFindOptions & _WKFindOptionsAtWordStarts)
3304         findOptions |= WebKit::FindOptionsAtWordStarts;
3305     if (wkFindOptions & _WKFindOptionsTreatMedialCapitalAsWordStart)
3306         findOptions |= WebKit::FindOptionsTreatMedialCapitalAsWordStart;
3307     if (wkFindOptions & _WKFindOptionsBackwards)
3308         findOptions |= WebKit::FindOptionsBackwards;
3309     if (wkFindOptions & _WKFindOptionsWrapAround)
3310         findOptions |= WebKit::FindOptionsWrapAround;
3311     if (wkFindOptions & _WKFindOptionsShowOverlay)
3312         findOptions |= WebKit::FindOptionsShowOverlay;
3313     if (wkFindOptions & _WKFindOptionsShowFindIndicator)
3314         findOptions |= WebKit::FindOptionsShowFindIndicator;
3315     if (wkFindOptions & _WKFindOptionsShowHighlight)
3316         findOptions |= WebKit::FindOptionsShowHighlight;
3317     if (wkFindOptions & _WKFindOptionsDetermineMatchIndex)
3318         findOptions |= WebKit::FindOptionsDetermineMatchIndex;
3319
3320     return static_cast<WebKit::FindOptions>(findOptions);
3321 }
3322
3323 - (void)_countStringMatches:(NSString *)string options:(_WKFindOptions)options maxCount:(NSUInteger)maxCount
3324 {
3325 #if PLATFORM(IOS)
3326     if (_customContentView) {
3327         [_customContentView web_countStringMatches:string options:options maxCount:maxCount];
3328         return;
3329     }
3330 #endif
3331     _page->countStringMatches(string, toFindOptions(options), maxCount);
3332 }
3333
3334 - (void)_findString:(NSString *)string options:(_WKFindOptions)options maxCount:(NSUInteger)maxCount
3335 {
3336 #if PLATFORM(IOS)
3337     if (_customContentView) {
3338         [_customContentView web_findString:string options:options maxCount:maxCount];
3339         return;
3340     }
3341 #endif
3342     _page->findString(string, toFindOptions(options), maxCount);
3343 }
3344
3345 - (void)_hideFindUI
3346 {
3347 #if PLATFORM(IOS)
3348     if (_customContentView) {
3349         [_customContentView web_hideFindUI];
3350         return;
3351     }
3352 #endif
3353     _page->hideFindUI();
3354 }
3355
3356 - (void)_saveBackForwardSnapshotForItem:(WKBackForwardListItem *)item
3357 {
3358     _page->recordNavigationSnapshot(item._item);
3359 }
3360
3361 - (id <_WKInputDelegate>)_inputDelegate
3362 {
3363     return _inputDelegate.getAutoreleased();
3364 }
3365
3366 - (id <_WKFormDelegate>)_formDelegate
3367 {
3368     return (id <_WKFormDelegate>)[self _inputDelegate];
3369 }
3370
3371 - (void)_setInputDelegate:(id <_WKInputDelegate>)inputDelegate
3372 {
3373     _inputDelegate = inputDelegate;
3374
3375     class FormClient : public API::FormClient {
3376     public:
3377         explicit FormClient(WKWebView *webView)
3378             : m_webView(webView)
3379         {
3380         }
3381
3382         virtual ~FormClient() { }
3383
3384         virtual void willSubmitForm(WebKit::WebPageProxy&, WebKit::WebFrameProxy&, WebKit::WebFrameProxy& sourceFrame, const Vector<std::pair<WTF::String, WTF::String>>& textFieldValues, API::Object* userData, Ref<WebKit::WebFormSubmissionListenerProxy>&& listener) override
3385         {
3386             if (userData && userData->type() != API::Object::Type::Data) {
3387                 ASSERT(!userData || userData->type() == API::Object::Type::Data);
3388                 m_webView->_page->process().connection()->markCurrentlyDispatchedMessageAsInvalid();
3389                 listener->continueSubmission();
3390                 return;
3391             }
3392
3393             auto inputDelegate = m_webView->_inputDelegate.get();
3394
3395             if (![inputDelegate respondsToSelector:@selector(_webView:willSubmitFormValues:userObject:submissionHandler:)]) {
3396                 listener->continueSubmission();
3397                 return;
3398             }
3399
3400             auto valueMap = adoptNS([[NSMutableDictionary alloc] initWithCapacity:textFieldValues.size()]);
3401             for (const auto& pair : textFieldValues)
3402                 [valueMap setObject:pair.second forKey:pair.first];
3403
3404             NSObject <NSSecureCoding> *userObject = nil;
3405             if (API::Data* data = static_cast<API::Data*>(userData)) {
3406                 auto nsData = adoptNS([[NSData alloc] initWithBytesNoCopy:const_cast<void*>(static_cast<const void*>(data->bytes())) length:data->size() freeWhenDone:NO]);
3407                 auto unarchiver = adoptNS([[NSKeyedUnarchiver alloc] initForReadingWithData:nsData.get()]);
3408                 [unarchiver setRequiresSecureCoding:YES];
3409                 @try {
3410                     userObject = [unarchiver decodeObjectOfClass:[NSObject class] forKey:@"userObject"];
3411                 } @catch (NSException *exception) {
3412                     LOG_ERROR("Failed to decode user data: %@", exception);
3413                 }
3414             }
3415
3416             RefPtr<WebKit::WebFormSubmissionListenerProxy> localListener = WTF::move(listener);
3417             RefPtr<WebKit::CompletionHandlerCallChecker> checker = WebKit::CompletionHandlerCallChecker::create(inputDelegate.get(), @selector(_webView:willSubmitFormValues:userObject:submissionHandler:));
3418             [inputDelegate _webView:m_webView willSubmitFormValues:valueMap.get() userObject:userObject submissionHandler:[localListener, checker] {
3419                 checker->didCallCompletionHandler();
3420                 localListener->continueSubmission();
3421             }];
3422         }
3423
3424     private:
3425         WKWebView *m_webView;
3426     };
3427
3428     if (inputDelegate)
3429         _page->setFormClient(std::make_unique<FormClient>(self));
3430     else
3431         _page->setFormClient(nullptr);
3432 }
3433
3434 - (void)_setFormDelegate:(id <_WKFormDelegate>)formDelegate
3435 {
3436     [self _setInputDelegate:(id <_WKInputDelegate>)formDelegate];
3437 }
3438
3439 - (BOOL)_isDisplayingStandaloneImageDocument
3440 {
3441     if (auto* mainFrame = _page->mainFrame())
3442         return mainFrame->isDisplayingStandaloneImageDocument();
3443     return NO;
3444 }
3445
3446 - (BOOL)_isDisplayingStandaloneMediaDocument
3447 {
3448     if (auto* mainFrame = _page->mainFrame())
3449         return mainFrame->isDisplayingStandaloneMediaDocument();
3450     return NO;
3451 }
3452
3453 - (BOOL)_isShowingNavigationGestureSnapshot
3454 {
3455     return _page->isShowingNavigationGestureSnapshot();
3456 }
3457
3458 - (_WKLayoutMode)_layoutMode
3459 {
3460 #if PLATFORM(MAC)
3461     switch (_impl->layoutMode()) {
3462     case kWKLayoutModeFixedSize:
3463         return _WKLayoutModeFixedSize;
3464     case kWKLayoutModeDynamicSizeComputedFromViewScale:
3465         return _WKLayoutModeDynamicSizeComputedFromViewScale;
3466     case kWKLayoutModeDynamicSizeComputedFromMinimumDocumentSize:
3467         return _WKLayoutModeDynamicSizeComputedFromMinimumDocumentSize;
3468     case kWKLayoutModeViewSize:
3469     default:
3470         return _WKLayoutModeViewSize;
3471     }
3472 #else
3473     return _page->useFixedLayout() ? _WKLayoutModeFixedSize : _WKLayoutModeViewSize;
3474 #endif
3475 }
3476
3477 - (void)_setLayoutMode:(_WKLayoutMode)layoutMode
3478 {
3479 #if PLATFORM(MAC)
3480     WKLayoutMode wkViewLayoutMode;
3481     switch (layoutMode) {
3482     case _WKLayoutModeFixedSize:
3483         wkViewLayoutMode = kWKLayoutModeFixedSize;
3484         break;
3485     case _WKLayoutModeDynamicSizeComputedFromViewScale:
3486         wkViewLayoutMode = kWKLayoutModeDynamicSizeComputedFromViewScale;
3487         break;
3488     case _WKLayoutModeDynamicSizeComputedFromMinimumDocumentSize:
3489         wkViewLayoutMode = kWKLayoutModeDynamicSizeComputedFromMinimumDocumentSize;
3490         break;
3491     case _WKLayoutModeViewSize:
3492     default:
3493         wkViewLayoutMode = kWKLayoutModeViewSize;
3494         break;
3495     }
3496     _impl->setLayoutMode(wkViewLayoutMode);
3497 #else
3498     _page->setUseFixedLayout(layoutMode == _WKLayoutModeFixedSize || layoutMode == _WKLayoutModeDynamicSizeComputedFromViewScale);
3499 #endif
3500 }
3501
3502 - (CGSize)_fixedLayoutSize
3503 {
3504     return _page->fixedLayoutSize();
3505 }
3506
3507 - (void)_setFixedLayoutSize:(CGSize)fixedLayoutSize
3508 {
3509     _page->setFixedLayoutSize(WebCore::expandedIntSize(WebCore::FloatSize(fixedLayoutSize)));
3510 }
3511
3512 - (CGFloat)_viewScale
3513 {
3514     return _page->viewScaleFactor();
3515 }
3516
3517 - (void)_setViewScale:(CGFloat)viewScale
3518 {
3519 #if PLATFORM(MAC)
3520     _impl->setViewScale(viewScale);
3521 #else
3522     if (viewScale <= 0 || isnan(viewScale) || isinf(viewScale))
3523         [NSException raise:NSInvalidArgumentException format:@"View scale should be a positive number"];
3524
3525     _page->scaleView(viewScale);
3526 #endif
3527 }
3528
3529 #pragma mark scrollperf methods
3530
3531 - (void)_setScrollPerformanceDataCollectionEnabled:(BOOL)enabled
3532 {
3533     _page->setScrollPerformanceDataCollectionEnabled(enabled);
3534 }
3535
3536 - (BOOL)_scrollPerformanceDataCollectionEnabled
3537 {
3538     return _page->scrollPerformanceDataCollectionEnabled();
3539 }
3540
3541 - (NSArray *)_scrollPerformanceData
3542 {
3543 #if PLATFORM(IOS)
3544     if (WebKit::RemoteLayerTreeScrollingPerformanceData* scrollPerfData = _page->scrollingPerformanceData())
3545         return scrollPerfData->data();
3546 #endif
3547     return nil;
3548 }
3549
3550 #pragma mark media playback restrictions
3551
3552 - (BOOL)_allowsMediaDocumentInlinePlayback
3553 {
3554 #if PLATFORM(IOS)
3555     return _page->allowsMediaDocumentInlinePlayback();
3556 #else
3557     return NO;
3558 #endif
3559 }
3560
3561 - (void)_setAllowsMediaDocumentInlinePlayback:(BOOL)flag
3562 {
3563 #if PLATFORM(IOS)
3564     _page->setAllowsMediaDocumentInlinePlayback(flag);
3565 #endif
3566 }
3567
3568 - (BOOL)_webProcessIsResponsive
3569 {
3570     return _page->process().responsivenessTimer().isResponsive();
3571 }
3572
3573 #pragma mark iOS-specific methods
3574
3575 #if PLATFORM(IOS)
3576
3577 - (CGSize)_minimumLayoutSizeOverride
3578 {
3579     ASSERT(_overridesMinimumLayoutSize);
3580     return _minimumLayoutSizeOverride;
3581 }
3582
3583 - (void)_setMinimumLayoutSizeOverride:(CGSize)minimumLayoutSizeOverride
3584 {
3585     _overridesMinimumLayoutSize = YES;
3586     if (CGSizeEqualToSize(_minimumLayoutSizeOverride, minimumLayoutSizeOverride))
3587         return;
3588
3589     _minimumLayoutSizeOverride = minimumLayoutSizeOverride;
3590     if (_dynamicViewportUpdateMode == DynamicViewportUpdateMode::NotResizing)
3591         _page->setViewportConfigurationMinimumLayoutSize(WebCore::FloatSize(minimumLayoutSizeOverride));
3592 }
3593
3594 - (UIEdgeInsets)_obscuredInsets
3595 {
3596     return _obscuredInsets;
3597 }
3598
3599 - (void)_setObscuredInsets:(UIEdgeInsets)obscuredInsets
3600 {
3601     ASSERT(obscuredInsets.top >= 0);
3602     ASSERT(obscuredInsets.left >= 0);
3603     ASSERT(obscuredInsets.bottom >= 0);
3604     ASSERT(obscuredInsets.right >= 0);
3605     
3606     _haveSetObscuredInsets = YES;
3607
3608     if (UIEdgeInsetsEqualToEdgeInsets(_obscuredInsets, obscuredInsets))
3609         return;
3610
3611     _obscuredInsets = obscuredInsets;
3612
3613     [self _updateVisibleContentRects];
3614 }
3615
3616 - (void)_setInterfaceOrientationOverride:(UIInterfaceOrientation)interfaceOrientation
3617 {
3618     if (!_overridesInterfaceOrientation)
3619         [[NSNotificationCenter defaultCenter] removeObserver:self name:UIWindowDidRotateNotification object:nil];
3620
3621     _overridesInterfaceOrientation = YES;
3622
3623     if (interfaceOrientation == _interfaceOrientationOverride)
3624         return;
3625
3626     _interfaceOrientationOverride = interfaceOrientation;
3627
3628     if (_dynamicViewportUpdateMode == DynamicViewportUpdateMode::NotResizing)
3629         _page->setDeviceOrientation(deviceOrientationForUIInterfaceOrientation(_interfaceOrientationOverride));
3630 }
3631
3632 - (UIInterfaceOrientation)_interfaceOrientationOverride
3633 {
3634     ASSERT(_overridesInterfaceOrientation);
3635     return _interfaceOrientationOverride;
3636 }
3637
3638 - (CGSize)_maximumUnobscuredSizeOverride
3639 {
3640     ASSERT(_overridesMaximumUnobscuredSize);
3641     return _maximumUnobscuredSizeOverride;
3642 }
3643
3644 - (void)_setMaximumUnobscuredSizeOverride:(CGSize)size
3645 {
3646     ASSERT(size.width <= self.bounds.size.width && size.height <= self.bounds.size.height);
3647     _overridesMaximumUnobscuredSize = YES;
3648     if (CGSizeEqualToSize(_maximumUnobscuredSizeOverride, size))
3649         return;
3650
3651     _maximumUnobscuredSizeOverride = size;
3652     if (_dynamicViewportUpdateMode == DynamicViewportUpdateMode::NotResizing)
3653         _page->setMaximumUnobscuredSize(WebCore::FloatSize(size));
3654 }
3655
3656 - (void)_setBackgroundExtendsBeyondPage:(BOOL)backgroundExtends
3657 {
3658     _page->setBackgroundExtendsBeyondPage(backgroundExtends);
3659 }
3660
3661 - (BOOL)_backgroundExtendsBeyondPage
3662 {
3663     return _page->backgroundExtendsBeyondPage();
3664 }
3665
3666 - (void)_beginInteractiveObscuredInsetsChange
3667 {
3668     ASSERT(!_isChangingObscuredInsetsInteractively);
3669     _isChangingObscuredInsetsInteractively = YES;
3670 }
3671
3672 - (void)_endInteractiveObscuredInsetsChange
3673 {
3674     ASSERT(_isChangingObscuredInsetsInteractively);
3675     _isChangingObscuredInsetsInteractively = NO;
3676     [self _updateVisibleContentRects];
3677 }
3678
3679 - (void)_hideContentUntilNextUpdate
3680 {
3681     if (auto* area = _page->drawingArea())
3682         area->hideContentUntilAnyUpdate();
3683 }
3684
3685 - (void)_beginAnimatedResizeWithUpdates:(void (^)(void))updateBlock
3686 {
3687     CGRect oldBounds = self.bounds;
3688     WebCore::FloatRect oldUnobscuredContentRect = _page->unobscuredContentRect();
3689
3690     if (_customContentView || !_hasCommittedLoadForMainFrame || CGRectIsEmpty(oldBounds) || oldUnobscuredContentRect.isEmpty()) {
3691         updateBlock();
3692         return;
3693     }
3694
3695     _dynamicViewportUpdateMode = DynamicViewportUpdateMode::ResizingWithAnimation;
3696
3697     WebCore::FloatSize oldMinimumLayoutSize = activeMinimumLayoutSize(self, oldBounds);
3698     WebCore::FloatSize oldMaximumUnobscuredSize = activeMaximumUnobscuredSize(self, oldBounds);
3699     int32_t oldOrientation = activeOrientation(self);
3700     UIEdgeInsets oldObscuredInsets = _obscuredInsets;
3701
3702     updateBlock();
3703
3704     CGRect newBounds = self.bounds;
3705     WebCore::FloatSize newMinimumLayoutSize = activeMinimumLayoutSize(self, newBounds);
3706     WebCore::FloatSize newMaximumUnobscuredSize = activeMaximumUnobscuredSize(self, newBounds);
3707     int32_t newOrientation = activeOrientation(self);
3708     UIEdgeInsets newObscuredInsets = _obscuredInsets;
3709     CGRect futureUnobscuredRectInSelfCoordinates = UIEdgeInsetsInsetRect(newBounds, _obscuredInsets);
3710     CGRect contentViewBounds = [_contentView bounds];
3711
3712     ASSERT_WITH_MESSAGE(!(_overridesMinimumLayoutSize && newMinimumLayoutSize.isEmpty()), "Clients controlling the layout size should maintain a valid layout size to minimize layouts.");
3713     if (CGRectIsEmpty(newBounds) || newMinimumLayoutSize.isEmpty() || CGRectIsEmpty(futureUnobscuredRectInSelfCoordinates) || CGRectIsEmpty(contentViewBounds)) {
3714         _dynamicViewportUpdateMode = DynamicViewportUpdateMode::NotResizing;
3715         [self _frameOrBoundsChanged];
3716         if (_overridesMinimumLayoutSize)
3717             _page->setViewportConfigurationMinimumLayoutSize(WebCore::FloatSize(newMinimumLayoutSize));
3718         if (_overridesMaximumUnobscuredSize)
3719             _page->setMaximumUnobscuredSize(WebCore::FloatSize(newMaximumUnobscuredSize));
3720         if (_overridesInterfaceOrientation)
3721             _page->setDeviceOrientation(newOrientation);
3722         [self _updateVisibleContentRects];
3723         return;
3724     }
3725
3726     if (CGRectEqualToRect(oldBounds, newBounds)
3727         && oldMinimumLayoutSize == newMinimumLayoutSize
3728         && oldMaximumUnobscuredSize == newMaximumUnobscuredSize
3729         && oldOrientation == newOrientation
3730         && UIEdgeInsetsEqualToEdgeInsets(oldObscuredInsets, newObscuredInsets)) {
3731         _dynamicViewportUpdateMode = DynamicViewportUpdateMode::NotResizing;
3732         [self _updateVisibleContentRects];
3733         return;
3734     }
3735
3736     _resizeAnimationTransformAdjustments = CATransform3DIdentity;
3737
3738     NSUInteger indexOfContentView = [[_scrollView subviews] indexOfObject:_contentView.get()];
3739     _resizeAnimationView = adoptNS([[UIView alloc] init]);
3740     [_scrollView insertSubview:_resizeAnimationView.get() atIndex:indexOfContentView];
3741     [_resizeAnimationView addSubview:_contentView.get()];
3742     [_resizeAnimationView addSubview:[_contentView unscaledView]];
3743
3744     CGSize contentSizeInContentViewCoordinates = contentViewBounds.size;
3745     [_scrollView setMinimumZoomScale:std::min(newMinimumLayoutSize.width() / contentSizeInContentViewCoordinates.width, [_scrollView minimumZoomScale])];
3746     [_scrollView setMaximumZoomScale:std::max(newMinimumLayoutSize.width() / contentSizeInContentViewCoordinates.width, [_scrollView maximumZoomScale])];
3747
3748     // Compute the new scale to keep the current content width in the scrollview.
3749     CGFloat oldWebViewWidthInContentViewCoordinates = oldUnobscuredContentRect.width();
3750     CGFloat visibleContentViewWidthInContentCoordinates = std::min(contentSizeInContentViewCoordinates.width, oldWebViewWidthInContentViewCoordinates);
3751     CGFloat targetScale = newMinimumLayoutSize.width() / visibleContentViewWidthInContentCoordinates;
3752     CGFloat resizeAnimationViewAnimationScale = targetScale / contentZoomScale(self);
3753     [_resizeAnimationView setTransform:CGAffineTransformMakeScale(resizeAnimationViewAnimationScale, resizeAnimationViewAnimationScale)];
3754
3755     // Compute a new position to keep the content centered.
3756     CGPoint originalContentCenter = oldUnobscuredContentRect.center();
3757     CGPoint originalContentCenterInSelfCoordinates = [self convertPoint:originalContentCenter fromView:_contentView.get()];
3758     CGPoint futureUnobscuredRectCenterInSelfCoordinates = CGPointMake(futureUnobscuredRectInSelfCoordinates.origin.x + futureUnobscuredRectInSelfCoordinates.size.width / 2, futureUnobscuredRectInSelfCoordinates.origin.y + futureUnobscuredRectInSelfCoordinates.size.height / 2);
3759
3760     CGPoint originalContentOffset = [_scrollView contentOffset];
3761     CGPoint contentOffset = originalContentOffset;
3762     contentOffset.x += (originalContentCenterInSelfCoordinates.x - futureUnobscuredRectCenterInSelfCoordinates.x);
3763     contentOffset.y += (originalContentCenterInSelfCoordinates.y - futureUnobscuredRectCenterInSelfCoordinates.y);
3764
3765     // Limit the new offset within the scrollview, we do not want to rubber band programmatically.
3766     CGSize futureContentSizeInSelfCoordinates = CGSizeMake(contentSizeInContentViewCoordinates.width * targetScale, contentSizeInContentViewCoordinates.height * targetScale);
3767     CGFloat maxHorizontalOffset = futureContentSizeInSelfCoordinates.width - newBounds.size.width + _obscuredInsets.right;
3768     contentOffset.x = std::min(contentOffset.x, maxHorizontalOffset);
3769     CGFloat maxVerticalOffset = futureContentSizeInSelfCoordinates.height - newBounds.size.height + _obscuredInsets.bottom;
3770     contentOffset.y = std::min(contentOffset.y, maxVerticalOffset);
3771
3772     contentOffset.x = std::max(contentOffset.x, -_obscuredInsets.left);
3773     contentOffset.y = std::max(contentOffset.y, -_obscuredInsets.top);
3774
3775     // Make the top/bottom edges "sticky" within 1 pixel.
3776     if (oldUnobscuredContentRect.maxY() > contentSizeInContentViewCoordinates.height - 1)
3777         contentOffset.y = maxVerticalOffset;
3778     if (oldUnobscuredContentRect.y() < 1)
3779         contentOffset.y = -_obscuredInsets.top;
3780
3781     // FIXME: if we have content centered after double tap to zoom, we should also try to keep that rect in view.
3782     [_scrollView setContentSize:roundScrollViewContentSize(*_page, futureContentSizeInSelfCoordinates)];
3783     [_scrollView setContentOffset:contentOffset];
3784
3785     CGRect visibleRectInContentCoordinates = [self convertRect:newBounds toView:_contentView.get()];
3786     CGRect unobscuredRectInContentCoordinates = [self convertRect:futureUnobscuredRectInSelfCoordinates toView:_contentView.get()];
3787
3788     _page->dynamicViewportSizeUpdate(newMinimumLayoutSize, newMaximumUnobscuredSize, visibleRectInContentCoordinates, unobscuredRectInContentCoordinates, futureUnobscuredRectInSelfCoordinates, targetScale, newOrientation);
3789     if (WebKit::DrawingAreaProxy* drawingArea = _page->drawingArea())
3790         drawingArea->setSize(WebCore::IntSize(newBounds.size), WebCore::IntSize(), WebCore::IntSize());
3791 }
3792
3793 - (void)_endAnimatedResize
3794 {
3795     if (_dynamicViewportUpdateMode == DynamicViewportUpdateMode::NotResizing)
3796         return;
3797
3798     _page->synchronizeDynamicViewportUpdate();
3799
3800     NSUInteger indexOfResizeAnimationView = [[_scrollView subviews] indexOfObject:_resizeAnimationView.get()];
3801     [_scrollView insertSubview:_contentView.get() atIndex:indexOfResizeAnimationView];
3802     [_scrollView insertSubview:[_contentView unscaledView] atIndex:indexOfResizeAnimationView + 1];
3803
3804     CALayer *contentViewLayer = [_contentView layer];
3805     CGFloat adjustmentScale = _resizeAnimationTransformAdjustments.m11;
3806     contentViewLayer.sublayerTransform = CATransform3DIdentity;
3807
3808     CGFloat animatingScaleTarget = [[_resizeAnimationView layer] transform].m11;
3809     CALayer *contentLayer = [_contentView layer];
3810     CATransform3D contentLayerTransform = contentLayer.transform;
3811     CGFloat currentScale = [[_resizeAnimationView layer] transform].m11 * contentLayerTransform.m11;
3812
3813     // We cannot use [UIScrollView setZoomScale:] directly because the UIScrollView delegate would get a callback with
3814     // an invalid contentOffset. The real content offset is only set below.
3815     // Since there is no public API for setting both the zoomScale and the contentOffset, we set the zoomScale manually
3816     // on the zoom layer and then only change the contentOffset.
3817     CGFloat adjustedScale = adjustmentScale * currentScale;
3818     contentLayerTransform.m11 = adjustedScale;
3819     contentLayerTransform.m22 = adjustedScale;
3820     contentLayer.transform = contentLayerTransform;
3821
3822     CGPoint currentScrollOffset = [_scrollView contentOffset];
3823     double horizontalScrollAdjustement = _resizeAnimationTransformAdjustments.m41 * animatingScaleTarget;
3824     double verticalScrollAdjustment = _resizeAnimationTransformAdjustments.m42 * animatingScaleTarget;
3825
3826     [_scrollView setContentSize:roundScrollViewContentSize(*_page, [_contentView frame].size)];
3827     [_scrollView setContentOffset:CGPointMake(currentScrollOffset.x - horizontalScrollAdjustement, currentScrollOffset.y - verticalScrollAdjustment)];
3828
3829     [_resizeAnimationView removeFromSuperview];
3830     _resizeAnimationView = nil;
3831     _resizeAnimationTransformAdjustments = CATransform3DIdentity;
3832
3833     _dynamicViewportUpdateMode = DynamicViewportUpdateMode::NotResizing;
3834     [_contentView setHidden:NO];
3835     [self _updateVisibleContentRects];
3836
3837     while (!_snapshotsDeferredDuringResize.isEmpty())
3838         _snapshotsDeferredDuringResize.takeLast()();
3839 }
3840
3841 - (void)_resizeWhileHidingContentWithUpdates:(void (^)(void))updateBlock
3842 {
3843     [self _beginAnimatedResizeWithUpdates:updateBlock];
3844     if (_dynamicViewportUpdateMode == DynamicViewportUpdateMode::ResizingWithAnimation) {
3845         [_contentView setHidden:YES];
3846         _dynamicViewportUpdateMode = DynamicViewportUpdateMode::ResizingWithDocumentHidden;
3847     }
3848 }
3849
3850 - (void)_setOverlaidAccessoryViewsInset:(CGSize)inset
3851 {
3852     [_customContentView web_setOverlaidAccessoryViewsInset:inset];
3853 }
3854
3855 - (void)_snapshotRect:(CGRect)rectInViewCoordinates intoImageOfWidth:(CGFloat)imageWidth completionHandler:(void(^)(CGImageRef))completionHandler
3856 {
3857     if (_dynamicViewportUpdateMode != DynamicViewportUpdateMode::NotResizing) {
3858         // Defer snapshotting until after the current resize completes.
3859         void (^copiedCompletionHandler)(CGImageRef) = [completionHandler copy];
3860         RetainPtr<WKWebView> retainedSelf = self;
3861         _snapshotsDeferredDuringResize.append([retainedSelf, rectInViewCoordinates, imageWidth, copiedCompletionHandler] {
3862             [retainedSelf _snapshotRect:rectInViewCoordinates intoImageOfWidth:imageWidth completionHandler:copiedCompletionHandler];
3863             [copiedCompletionHandler release];
3864         });
3865         return;
3866     }
3867
3868     CGRect snapshotRectInContentCoordinates = [self convertRect:rectInViewCoordinates toView:self._currentContentView];
3869     CGFloat imageScale = imageWidth / snapshotRectInContentCoordinates.size.width;
3870     CGFloat imageHeight = imageScale * snapshotRectInContentCoordinates.size.height;
3871     CGSize imageSize = CGSizeMake(imageWidth, imageHeight);
3872
3873 #if USE(IOSURFACE)
3874     // If we are parented and thus won't incur a significant penalty from paging in tiles, snapshot the view hierarchy directly.
3875     if (CADisplay *display = self.window.screen._display) {
3876         auto surface = WebCore::IOSurface::create(WebCore::expandedIntSize(WebCore::FloatSize(imageSize)), WebCore::ColorSpaceSRGB);
3877         CGFloat imageScaleInViewCoordinates = imageWidth / rectInViewCoordinates.size.width;
3878         CATransform3D transform = CATransform3DMakeScale(imageScaleInViewCoordinates, imageScaleInViewCoordinates, 1);
3879         transform = CATransform3DTranslate(transform, -rectInViewCoordinates.origin.x, -rectInViewCoordinates.origin.y, 0);
3880         CARenderServerRenderDisplayLayerWithTransformAndTimeOffset(MACH_PORT_NULL, (CFStringRef)display.name, self.layer.context.contextId, reinterpret_cast<uint64_t>(self.layer), surface->surface(), 0, 0, &transform, 0);
3881         completionHandler(surface->createImage().get());
3882         return;
3883     }
3884 #endif
3885     
3886     if (_customContentView) {
3887         UIGraphicsBeginImageContextWithOptions(imageSize, YES, 1);
3888
3889         UIView *customContentView = _customContentView.get();
3890         [customContentView.backgroundColor set];
3891         UIRectFill(CGRectMake(0, 0, imageWidth, imageHeight));
3892
3893         CGContextRef context = UIGraphicsGetCurrentContext();
3894         CGContextTranslateCTM(context, -snapshotRectInContentCoordinates.origin.x * imageScale, -snapshotRectInContentCoordinates.origin.y * imageScale);
3895         CGContextScaleCTM(context, imageScale, imageScale);
3896         [customContentView.layer renderInContext:context];
3897
3898         completionHandler([UIGraphicsGetImageFromCurrentImageContext() CGImage]);
3899
3900         UIGraphicsEndImageContext();
3901         return;
3902     }
3903
3904     void(^copiedCompletionHandler)(CGImageRef) = [completionHandler copy];
3905     _page->takeSnapshot(WebCore::enclosingIntRect(snapshotRectInContentCoordinates), WebCore::expandedIntSize(WebCore::FloatSize(imageSize)), WebKit::SnapshotOptionsExcludeDeviceScaleFactor, [=](const WebKit::ShareableBitmap::Handle& imageHandle, WebKit::CallbackBase::Error) {
3906         if (imageHandle.isNull()) {
3907             copiedCompletionHandler(nullptr);
3908             [copiedCompletionHandler release];
3909             return;
3910         }
3911
3912         RefPtr<WebKit::ShareableBitmap> bitmap = WebKit::ShareableBitmap::create(imageHandle, WebKit::SharedMemory::Protection::ReadOnly);
3913
3914         if (!bitmap) {
3915             copiedCompletionHandler(nullptr);
3916             [copiedCompletionHandler release];
3917             return;
3918         }
3919
3920         RetainPtr<CGImageRef> cgImage;
3921         cgImage = bitmap->makeCGImage();
3922         copiedCompletionHandler(cgImage.get());
3923         [copiedCompletionHandler release];
3924     });
3925 }
3926
3927 - (void)_overrideLayoutParametersWithMinimumLayoutSize:(CGSize)minimumLayoutSize minimumLayoutSizeForMinimalUI:(CGSize)minimumLayoutSizeForMinimalUI maximumUnobscuredSizeOverride:(CGSize)maximumUnobscuredSizeOverride
3928 {
3929     UNUSED_PARAM(minimumLayoutSizeForMinimalUI);
3930     [self _overrideLayoutParametersWithMinimumLayoutSize:minimumLayoutSize maximumUnobscuredSizeOverride:maximumUnobscuredSizeOverride];
3931 }
3932
3933 - (void)_overrideLayoutParametersWithMinimumLayoutSize:(CGSize)minimumLayoutSize maximumUnobscuredSizeOverride:(CGSize)maximumUnobscuredSizeOverride
3934 {
3935     [self _setMinimumLayoutSizeOverride:minimumLayoutSize];
3936     [self _setMaximumUnobscuredSizeOverride:maximumUnobscuredSizeOverride];
3937 }
3938
3939 - (UIView *)_viewForFindUI
3940 {
3941     return [self viewForZoomingInScrollView:[self scrollView]];
3942 }
3943
3944 - (BOOL)_isDisplayingPDF
3945 {
3946     return [_customContentView isKindOfClass:[WKPDFView class]];
3947 }
3948
3949 - (NSData *)_dataForDisplayedPDF
3950 {
3951     if (![self _isDisplayingPDF])
3952         return nil;
3953     CGPDFDocumentRef pdfDocument = [(WKPDFView *)_customContentView pdfDocument];
3954     return [(NSData *)CGDataProviderCopyData(CGPDFDocumentGetDataProvider(pdfDocument)) autorelease];
3955 }
3956
3957 - (NSString *)_suggestedFilenameForDisplayedPDF
3958 {
3959     if (![self _isDisplayingPDF])
3960         return nil;
3961     return [(WKPDFView *)_customContentView.get() suggestedFilename];
3962 }
3963
3964 - (BOOL)_allowsDoubleTapGestures
3965 {
3966     if (_fastClickingIsDisabled)
3967         return YES;
3968
3969     // If the page is not user scalable, we don't allow double tap gestures.
3970     if (![_scrollView isZoomEnabled] || [_scrollView minimumZoomScale] >= [_scrollView maximumZoomScale])
3971         return NO;
3972
3973     // For scalable viewports, only disable double tap gestures if the viewport width is device width.
3974     if (_viewportMetaTagWidth != WebCore::ViewportArguments::ValueDeviceWidth)
3975         return YES;
3976
3977     return !areEssentiallyEqualAsFloat(contentZoomScale(self), _initialScaleFactor);
3978 }
3979
3980 - (_WKWebViewPrintFormatter *)_webViewPrintFormatter
3981 {
3982     UIViewPrintFormatter *viewPrintFormatter = self.viewPrintFormatter;
3983     ASSERT([viewPrintFormatter isKindOfClass:[_WKWebViewPrintFormatter class]]);
3984     return (_WKWebViewPrintFormatter *)viewPrintFormatter;
3985 }
3986
3987 #else // #if PLATFORM(IOS)
3988
3989 #pragma mark - OS X-specific methods
3990
3991 - (BOOL)_drawsBackground
3992 {
3993     return _impl->drawsBackground();
3994 }
3995
3996 - (void)_setDrawsBackground:(BOOL)drawsBackground
3997 {
3998     _impl->setDrawsBackground(drawsBackground);
3999 }
4000
4001 #if WK_API_ENABLED
4002 - (NSView *)_inspectorAttachmentView
4003 {
4004     return _impl->inspectorAttachmentView();
4005 }
4006
4007 - (void)_setInspectorAttachmentView:(NSView *)newView
4008 {
4009     _impl->setInspectorAttachmentView(newView);
4010 }
4011 #endif
4012
4013 - (BOOL)_windowOcclusionDetectionEnabled
4014 {
4015     return _impl->windowOcclusionDetectionEnabled();
4016 }
4017
4018 - (void)_setWindowOcclusionDetectionEnabled:(BOOL)enabled
4019 {
4020     _impl->setWindowOcclusionDetectionEnabled(enabled);
4021 }
4022
4023 - (void)_setOverrideDeviceScaleFactor:(CGFloat)deviceScaleFactor
4024 {
4025     _impl->setOverrideDeviceScaleFactor(deviceScaleFactor);
4026 }
4027
4028 - (CGFloat)_overrideDeviceScaleFactor
4029 {
4030     return _impl->overrideDeviceScaleFactor();
4031 }
4032
4033 - (void)_setTopContentInset:(CGFloat)contentInset
4034 {
4035     return _impl->setTopContentInset(contentInset);
4036 }
4037
4038 - (CGFloat)_topContentInset
4039 {
4040     return _impl->topContentInset();
4041 }
4042
4043 - (NSColor *)_pageExtendedBackgroundColor
4044 {
4045     return _impl->pageExtendedBackgroundColor();
4046 }
4047
4048 - (id)_immediateActionAnimationControllerForHitTestResult:(_WKHitTestResult *)hitTestResult withType:(_WKImmediateActionType)type userData:(id<NSSecureCoding>)userData
4049 {
4050     return nil;
4051 }
4052
4053 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
4054 - (void)_setAutomaticallyAdjustsContentInsets:(BOOL)automaticallyAdjustsContentInsets
4055 {
4056     _impl->setAutomaticallyAdjustsContentInsets(automaticallyAdjustsContentInsets);
4057 }
4058
4059 - (BOOL)_automaticallyAdjustsContentInsets
4060 {
4061     return _impl->automaticallyAdjustsContentInsets();
4062 }
4063 #endif
4064
4065 - (CGFloat)_minimumLayoutWidth
4066 {
4067     return _page->minimumLayoutSize().width();
4068 }
4069
4070 - (void)_setMinimumLayoutWidth:(CGFloat)width
4071 {
4072     BOOL expandsToFit = width > 0;
4073
4074     _page->setMinimumLayoutSize(WebCore::IntSize(width, 0));
4075     _page->setMainFrameIsScrollable(!expandsToFit);
4076
4077     _impl->setClipsToVisibleRect(expandsToFit);
4078 }
4079
4080 - (NSPrintOperation *)_printOperationWithPrintInfo:(NSPrintInfo *)printInfo
4081 {
4082     if (auto webFrameProxy = _page->mainFrame())
4083         return _impl->printOperationWithPrintInfo(printInfo, *webFrameProxy);
4084     return nil;
4085 }
4086
4087 - (NSPrintOperation *)_printOperationWithPrintInfo:(NSPrintInfo *)printInfo forFrame:(_WKFrameHandle *)frameHandle
4088 {
4089     if (auto webFrameProxy = _page->process().webFrame(frameHandle._frameID))
4090         return _impl->printOperationWithPrintInfo(printInfo, *webFrameProxy);
4091     return nil;
4092 }
4093
4094 #endif
4095
4096 @end
4097
4098
4099 @implementation WKWebView (WKTesting)
4100
4101 #if PLATFORM(IOS)
4102
4103 - (CGRect)_contentVisibleRect
4104 {
4105     return [self convertRect:[self bounds] toView:self._currentContentView];
4106 }
4107
4108 - (CGPoint)_convertPointFromContentsToView:(CGPoint)point
4109 {
4110     return [self convertPoint:point fromView:self._currentContentView];
4111 }
4112
4113 - (CGPoint)_convertPointFromViewToContents:(CGPoint)point
4114 {
4115     return [self convertPoint:point toView:self._currentContentView];
4116 }
4117
4118 #endif // PLATFORM(IOS)
4119
4120 // Execute the supplied block after the next transaction from the WebProcess.
4121 - (void)_doAfterNextPresentationUpdate:(void (^)(void))updateBlock
4122 {
4123     void (^updateBlockCopy)(void) = nil;
4124     if (updateBlock)
4125         updateBlockCopy = Block_copy(updateBlock);
4126
4127     _page->callAfterNextPresentationUpdate([updateBlockCopy](WebKit::CallbackBase::Error error) {
4128         if (updateBlockCopy) {
4129             updateBlockCopy();
4130             Block_release(updateBlockCopy);
4131         }
4132     });
4133 }
4134
4135 @end
4136
4137
4138 #if PLATFORM(MAC)
4139
4140 @implementation WKWebView (WKIBActions)
4141
4142 - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
4143 {
4144     SEL action = item.action;
4145
4146     if (action == @selector(goBack:))
4147         return !!_page->backForwardList().backItem();
4148
4149     if (action == @selector(goForward:))
4150         return !!_page->backForwardList().forwardItem();
4151
4152     if (action == @selector(stopLoading:)) {
4153         // FIXME: Return no if we're stopped.
4154         return YES;
4155     }
4156
4157     if (action == @selector(reload:) || action == @selector(reloadFromOrigin:)) {
4158         // FIXME: Return no if we're loading.
4159         return YES;
4160     }
4161
4162     return _impl->validateUserInterfaceItem(item);
4163 }
4164
4165 - (IBAction)goBack:(id)sender