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