Dispatch pointercancel events when content is panned or zoomed on iOS
[WebKit-https.git] / Source / WebKit / UIProcess / API / Cocoa / WKWebView.mm
1 /*
2  * Copyright (C) 2014-2018 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 "DynamicViewportSizeUpdate.h"
37 #import "FindClient.h"
38 #import "FrontBoardServicesSPI.h"
39 #import "FullscreenClient.h"
40 #import "GlobalFindInPageState.h"
41 #import "IconLoadingDelegate.h"
42 #import "LegacySessionStateCoding.h"
43 #import "Logging.h"
44 #import "MediaCaptureUtilities.h"
45 #import "NavigationState.h"
46 #import "ObjCObjectGraph.h"
47 #import "PageClient.h"
48 #import "ProvisionalPageProxy.h"
49 #import "RemoteLayerTreeScrollingPerformanceData.h"
50 #import "RemoteLayerTreeTransaction.h"
51 #import "RemoteObjectRegistry.h"
52 #import "RemoteObjectRegistryMessages.h"
53 #import "SafeBrowsingWarning.h"
54 #import "StringUtilities.h"
55 #import "UIDelegate.h"
56 #import "UserMediaProcessManager.h"
57 #import "VersionChecks.h"
58 #import "ViewGestureController.h"
59 #import "ViewSnapshotStore.h"
60 #import "WKBackForwardListInternal.h"
61 #import "WKBackForwardListItemInternal.h"
62 #import "WKBrowsingContextHandleInternal.h"
63 #import "WKDragDestinationAction.h"
64 #import "WKErrorInternal.h"
65 #import "WKHistoryDelegatePrivate.h"
66 #import "WKLayoutMode.h"
67 #import "WKNSData.h"
68 #import "WKNSURLExtras.h"
69 #import "WKNavigationDelegate.h"
70 #import "WKNavigationInternal.h"
71 #import "WKPreferencesInternal.h"
72 #import "WKProcessPoolInternal.h"
73 #import "WKSafeBrowsingWarning.h"
74 #import "WKSharedAPICast.h"
75 #import "WKSnapshotConfiguration.h"
76 #import "WKUIDelegate.h"
77 #import "WKUIDelegatePrivate.h"
78 #import "WKUserContentControllerInternal.h"
79 #import "WKWebViewConfigurationInternal.h"
80 #import "WKWebViewContentProvider.h"
81 #import "WKWebsiteDataStoreInternal.h"
82 #import "WebBackForwardList.h"
83 #import "WebCertificateInfo.h"
84 #import "WebFullScreenManagerProxy.h"
85 #import "WebPageGroup.h"
86 #import "WebPageProxy.h"
87 #import "WebPreferencesKeys.h"
88 #import "WebProcessPool.h"
89 #import "WebProcessProxy.h"
90 #import "WebURLSchemeHandlerCocoa.h"
91 #import "WebViewImpl.h"
92 #import "_WKActivatedElementInfoInternal.h"
93 #import "_WKDiagnosticLoggingDelegate.h"
94 #import "_WKFindDelegate.h"
95 #import "_WKFrameHandleInternal.h"
96 #import "_WKFullscreenDelegate.h"
97 #import "_WKHitTestResultInternal.h"
98 #import "_WKInputDelegate.h"
99 #import "_WKInspectorInternal.h"
100 #import "_WKRemoteObjectRegistryInternal.h"
101 #import "_WKSessionStateInternal.h"
102 #import "_WKVisitedLinkStoreInternal.h"
103 #import "_WKWebsitePoliciesInternal.h"
104 #import <WebCore/GraphicsContextCG.h>
105 #import <WebCore/IOSurface.h>
106 #import <WebCore/JSDOMBinding.h>
107 #import <WebCore/JSDOMExceptionHandling.h>
108 #import <WebCore/MIMETypeRegistry.h>
109 #import <WebCore/PlatformScreen.h>
110 #import <WebCore/RuntimeApplicationChecks.h>
111 #import <WebCore/SQLiteDatabaseTracker.h>
112 #import <WebCore/SchemeRegistry.h>
113 #import <WebCore/Settings.h>
114 #import <WebCore/SharedBuffer.h>
115 #import <WebCore/ValidationBubble.h>
116 #import <WebCore/ViewportArguments.h>
117 #import <WebCore/WritingMode.h>
118 #import <pal/spi/cocoa/NSKeyedArchiverSPI.h>
119 #import <pal/spi/mac/NSTextFinderSPI.h>
120 #import <wtf/BlockPtr.h>
121 #import <wtf/HashMap.h>
122 #import <wtf/MathExtras.h>
123 #import <wtf/NeverDestroyed.h>
124 #import <wtf/Optional.h>
125 #import <wtf/RetainPtr.h>
126 #import <wtf/SetForScope.h>
127 #import <wtf/UUID.h>
128 #import <wtf/spi/darwin/dyldSPI.h>
129 #import <wtf/text/TextStream.h>
130
131 #if ENABLE(APPLICATION_MANIFEST)
132 #import "_WKApplicationManifestInternal.h"
133 #endif
134
135 #if ENABLE(DATA_DETECTION)
136 #import "WKDataDetectorTypesInternal.h"
137 #endif
138
139 #if PLATFORM(IOS_FAMILY)
140 #import "InteractionInformationAtPosition.h"
141 #import "InteractionInformationRequest.h"
142 #import "ProcessThrottler.h"
143 #import "RemoteLayerTreeDrawingAreaProxy.h"
144 #import "RemoteScrollingCoordinatorProxy.h"
145 #import "UIKitSPI.h"
146 #import "VideoFullscreenManagerProxy.h"
147 #import "WKContentViewInteraction.h"
148 #import "WKPasswordView.h"
149 #import "WKScrollView.h"
150 #import "WKWebViewContentProviderRegistry.h"
151 #import "_WKWebViewPrintFormatter.h"
152 #import <MobileCoreServices/MobileCoreServices.h>
153 #import <UIKit/UIApplication.h>
154 #import <WebCore/FrameLoaderTypes.h>
155 #import <WebCore/InspectorOverlay.h>
156 #import <WebCore/ScrollableArea.h>
157 #import <WebCore/WebBackgroundTaskController.h>
158 #import <WebCore/WebSQLiteDatabaseTrackerClient.h>
159 #import <pal/spi/cg/CoreGraphicsSPI.h>
160 #import <pal/spi/cocoa/QuartzCoreSPI.h>
161 #import <pal/spi/ios/GraphicsServicesSPI.h>
162 #import <wtf/cocoa/Entitlements.h>
163
164 #define RELEASE_LOG_IF_ALLOWED(...) RELEASE_LOG_IF(_page && _page->isAlwaysOnLoggingAllowed(), ViewState, __VA_ARGS__)
165
166 @interface UIView (UIViewInternal)
167 - (UIViewController *)_viewControllerForAncestor;
168 @end
169
170 @interface UIWindow (UIWindowInternal)
171 - (BOOL)_isHostedInAnotherProcess;
172 @end
173
174 @interface UIViewController (UIViewControllerInternal)
175 - (UIViewController *)_rootAncestorViewController;
176 - (UIViewController *)_viewControllerForSupportedInterfaceOrientations;
177 @end
178
179 #endif // PLATFORM(IOS_FAMILY)
180
181 #if PLATFORM(IOS_FAMILY)
182 static const uint32_t firstSDKVersionWithLinkPreviewEnabledByDefault = 0xA0000;
183 static const Seconds delayBeforeNoVisibleContentsRectsLogging = 1_s;
184 #endif
185
186 #if PLATFORM(MAC)
187 #import "AppKitSPI.h"
188 #import "WKTextFinderClient.h"
189 #import "WKViewInternal.h"
190 #import <WebCore/ColorMac.h>
191
192 @interface WKWebView () <WebViewImplDelegate, NSTextInputClient, NSTextInputClient_Async>
193 @end
194
195 #if HAVE(TOUCH_BAR)
196 @interface WKWebView () <NSTouchBarProvider>
197 @end
198 #endif // HAVE(TOUCH_BAR)
199 #endif // PLATFORM(MAC)
200
201 #if ENABLE(ACCESSIBILITY_EVENTS)
202 #import "AccessibilitySupportSPI.h"
203 #import <wtf/darwin/WeakLinking.h>
204 #endif
205
206 #if PLATFORM(MAC) && ENABLE(DRAG_SUPPORT)
207
208 @interface WKWebView () <NSFilePromiseProviderDelegate, NSDraggingSource>
209 @end
210
211 #endif
212
213 static HashMap<WebKit::WebPageProxy*, __unsafe_unretained WKWebView *>& pageToViewMap()
214 {
215     static NeverDestroyed<HashMap<WebKit::WebPageProxy*, __unsafe_unretained WKWebView *>> map;
216     return map;
217 }
218
219 WKWebView* fromWebPageProxy(WebKit::WebPageProxy& page)
220 {
221     return pageToViewMap().get(&page);
222 }
223
224 #if PLATFORM(MAC)
225 static _WKOverlayScrollbarStyle toAPIScrollbarStyle(Optional<WebCore::ScrollbarOverlayStyle> coreScrollbarStyle)
226 {
227     if (!coreScrollbarStyle)
228         return _WKOverlayScrollbarStyleAutomatic;
229     
230     switch (coreScrollbarStyle.value()) {
231     case WebCore::ScrollbarOverlayStyleDark:
232         return _WKOverlayScrollbarStyleDark;
233     case WebCore::ScrollbarOverlayStyleLight:
234         return _WKOverlayScrollbarStyleLight;
235     case WebCore::ScrollbarOverlayStyleDefault:
236         return _WKOverlayScrollbarStyleDefault;
237     }
238     ASSERT_NOT_REACHED();
239     return _WKOverlayScrollbarStyleAutomatic;
240 }
241
242 static Optional<WebCore::ScrollbarOverlayStyle> toCoreScrollbarStyle(_WKOverlayScrollbarStyle scrollbarStyle)
243 {
244     switch (scrollbarStyle) {
245     case _WKOverlayScrollbarStyleDark:
246         return WebCore::ScrollbarOverlayStyleDark;
247     case _WKOverlayScrollbarStyleLight:
248         return WebCore::ScrollbarOverlayStyleLight;
249     case _WKOverlayScrollbarStyleDefault:
250         return WebCore::ScrollbarOverlayStyleDefault;
251     case _WKOverlayScrollbarStyleAutomatic:
252         break;
253     }
254     return WTF::nullopt;
255 }
256 #endif
257
258 #define FORWARD_ACTION_TO_WKCONTENTVIEW(_action) \
259     - (void)_action:(id)sender \
260     { \
261         if (self.usesStandardContentView) \
262             [_contentView _action ## ForWebView:sender]; \
263     }
264
265 @implementation WKWebView {
266     std::unique_ptr<WebKit::NavigationState> _navigationState;
267     std::unique_ptr<WebKit::UIDelegate> _uiDelegate;
268     std::unique_ptr<WebKit::IconLoadingDelegate> _iconLoadingDelegate;
269
270     _WKRenderingProgressEvents _observedRenderingProgressEvents;
271
272     WeakObjCPtr<id <_WKInputDelegate>> _inputDelegate;
273
274     Optional<BOOL> _resolutionForShareSheetImmediateCompletionForTesting;
275     RetainPtr<WKSafeBrowsingWarning> _safeBrowsingWarning;
276
277 #if PLATFORM(IOS_FAMILY)
278     RetainPtr<_WKRemoteObjectRegistry> _remoteObjectRegistry;
279
280     RetainPtr<WKScrollView> _scrollView;
281     RetainPtr<WKContentView> _contentView;
282
283 #if ENABLE(FULLSCREEN_API)
284     RetainPtr<WKFullScreenWindowController> _fullScreenWindowController;
285 #endif
286
287     BOOL _overridesViewLayoutSize;
288     CGSize _viewLayoutSizeOverride;
289     Optional<WebCore::FloatSize> _lastSentViewLayoutSize;
290     BOOL _overridesMaximumUnobscuredSize;
291     CGSize _maximumUnobscuredSizeOverride;
292     Optional<WebCore::FloatSize> _lastSentMaximumUnobscuredSize;
293     CGRect _inputViewBounds;
294     CGFloat _viewportMetaTagWidth;
295     BOOL _viewportMetaTagWidthWasExplicit;
296     BOOL _viewportMetaTagCameFromImageDocument;
297     CGFloat _initialScaleFactor;
298     BOOL _fastClickingIsDisabled;
299
300     BOOL _allowsLinkPreview;
301
302     UIEdgeInsets _obscuredInsets;
303     BOOL _haveSetObscuredInsets;
304     BOOL _isChangingObscuredInsetsInteractively;
305
306     UIEdgeInsets _unobscuredSafeAreaInsets;
307     BOOL _haveSetUnobscuredSafeAreaInsets;
308     BOOL _avoidsUnsafeArea;
309     UIRectEdge _obscuredInsetEdgesAffectedBySafeArea;
310
311     UIInterfaceOrientation _interfaceOrientationOverride;
312     BOOL _overridesInterfaceOrientation;
313     Optional<int32_t> _lastSentDeviceOrientation;
314
315     BOOL _allowsViewportShrinkToFit;
316
317     BOOL _hasCommittedLoadForMainFrame;
318     BOOL _needsResetViewStateAfterCommitLoadForMainFrame;
319     uint64_t _firstPaintAfterCommitLoadTransactionID;
320     WebKit::DynamicViewportUpdateMode _dynamicViewportUpdateMode;
321     WebKit::DynamicViewportSizeUpdateID _currentDynamicViewportSizeUpdateID;
322     CATransform3D _resizeAnimationTransformAdjustments;
323     CGFloat _animatedResizeOriginalContentWidth;
324     RetainPtr<UIView> _resizeAnimationView;
325     CGFloat _lastAdjustmentForScroller;
326     Optional<CGRect> _frozenVisibleContentRect;
327     Optional<CGRect> _frozenUnobscuredContentRect;
328
329     BOOL _commitDidRestoreScrollPosition;
330     Optional<WebCore::FloatPoint> _scrollOffsetToRestore;
331     WebCore::FloatBoxExtent _obscuredInsetsWhenSaved;
332
333     Optional<WebCore::FloatPoint> _unobscuredCenterToRestore;
334     Optional<uint64_t> _firstTransactionIDAfterPageRestore;
335     double _scaleToRestore;
336
337     std::unique_ptr<WebKit::ViewGestureController> _gestureController;
338     BOOL _allowsBackForwardNavigationGestures;
339
340     RetainPtr<UIView <WKWebViewContentProvider>> _customContentView;
341     RetainPtr<UIView> _customContentFixedOverlayView;
342
343     RetainPtr<NSTimer> _enclosingScrollViewScrollTimer;
344     BOOL _didScrollSinceLastTimerFire;
345
346     WebCore::Color _scrollViewBackgroundColor;
347
348     // This value tracks the current adjustment added to the bottom inset due to the keyboard sliding out from the bottom
349     // when computing obscured content insets. This is used when updating the visible content rects where we should not
350     // include this adjustment.
351     CGFloat _totalScrollViewBottomInsetAdjustmentForKeyboard;
352     BOOL _currentlyAdjustingScrollViewInsetsForKeyboard;
353
354     BOOL _delayUpdateVisibleContentRects;
355     BOOL _hadDelayedUpdateVisibleContentRects;
356
357     BOOL _waitingForEndAnimatedResize;
358     BOOL _waitingForCommitAfterAnimatedResize;
359
360     Vector<WTF::Function<void ()>> _callbacksDeferredDuringResize;
361     RetainPtr<NSMutableArray> _stableStatePresentationUpdateCallbacks;
362
363     RetainPtr<WKPasswordView> _passwordView;
364
365     BOOL _hasScheduledVisibleRectUpdate;
366     BOOL _visibleContentRectUpdateScheduledFromScrollViewInStableState;
367     Vector<BlockPtr<void ()>> _visibleContentRectUpdateCallbacks;
368
369     _WKDragInteractionPolicy _dragInteractionPolicy;
370
371     // For release-logging for <rdar://problem/39281269>.
372     MonotonicTime _timeOfRequestForVisibleContentRectUpdate;
373     MonotonicTime _timeOfLastVisibleContentRectUpdate;
374
375     NSUInteger _focusPreservationCount;
376     NSUInteger _activeFocusedStateRetainCount;
377 #endif
378 #if PLATFORM(MAC)
379     std::unique_ptr<WebKit::WebViewImpl> _impl;
380     RetainPtr<WKTextFinderClient> _textFinderClient;
381 #endif
382     _WKSelectionAttributes _selectionAttributes;
383     CGFloat _minimumEffectiveDeviceWidth;
384 }
385
386 - (instancetype)initWithFrame:(CGRect)frame
387 {
388     return [self initWithFrame:frame configuration:adoptNS([[WKWebViewConfiguration alloc] init]).get()];
389 }
390
391 - (BOOL)_isValid
392 {
393     return _page && _page->isValid();
394 }
395
396 #if PLATFORM(IOS_FAMILY)
397 static int32_t deviceOrientationForUIInterfaceOrientation(UIInterfaceOrientation orientation)
398 {
399     switch (orientation) {
400     case UIInterfaceOrientationUnknown:
401     case UIInterfaceOrientationPortrait:
402         return 0;
403     case UIInterfaceOrientationPortraitUpsideDown:
404         return 180;
405     case UIInterfaceOrientationLandscapeLeft:
406         return -90;
407     case UIInterfaceOrientationLandscapeRight:
408         return 90;
409     }
410 }
411
412 static int32_t deviceOrientation()
413 {
414     return deviceOrientationForUIInterfaceOrientation([[UIApplication sharedApplication] statusBarOrientation]);
415 }
416
417 - (BOOL)_isShowingVideoPictureInPicture
418 {
419 #if !HAVE(AVKIT)
420     return false;
421 #else
422     if (!_page || !_page->videoFullscreenManager())
423         return false;
424
425     return _page->videoFullscreenManager()->hasMode(WebCore::HTMLMediaElementEnums::VideoFullscreenModePictureInPicture);
426 #endif
427 }
428
429 - (BOOL)_mayAutomaticallyShowVideoPictureInPicture
430 {
431 #if !HAVE(AVKIT)
432     return false;
433 #else
434     if (!_page || !_page->videoFullscreenManager())
435         return false;
436
437     return _page->videoFullscreenManager()->mayAutomaticallyShowVideoPictureInPicture();
438 #endif
439 }
440
441 static bool shouldAllowPictureInPictureMediaPlayback()
442 {
443     static bool shouldAllowPictureInPictureMediaPlayback = dyld_get_program_sdk_version() >= DYLD_IOS_VERSION_9_0;
444     return shouldAllowPictureInPictureMediaPlayback;
445 }
446
447 static bool shouldAllowSettingAnyXHRHeaderFromFileURLs()
448 {
449     static bool shouldAllowSettingAnyXHRHeaderFromFileURLs = (WebCore::IOSApplication::isCardiogram() || WebCore::IOSApplication::isNike()) && !linkedOnOrAfter(WebKit::SDKVersion::FirstThatDisallowsSettingAnyXHRHeaderFromFileURLs);
450     return shouldAllowSettingAnyXHRHeaderFromFileURLs;
451 }
452
453 - (void)_incrementFocusPreservationCount
454 {
455     ++_focusPreservationCount;
456 }
457
458 - (void)_decrementFocusPreservationCount
459 {
460     if (_focusPreservationCount)
461         --_focusPreservationCount;
462 }
463
464 - (void)_resetFocusPreservationCount
465 {
466     _focusPreservationCount = 0;
467 }
468
469 - (BOOL)_isRetainingActiveFocusedState
470 {
471     // Focus preservation count fulfills the same role as active focus state count.
472     // However, unlike active focus state, it may be reset to 0 without impacting the
473     // behavior of -_retainActiveFocusedState, and it's harmless to invoke
474     // -_decrementFocusPreservationCount after resetting the count to 0.
475     return _focusPreservationCount || _activeFocusedStateRetainCount;
476 }
477
478 #endif
479
480 #if USE(APPLE_INTERNAL_SDK)
481 #include <WebKitAdditions/WKWebViewInternalAdditions.mm>
482 #endif
483
484 static bool shouldRequireUserGestureToLoadVideo()
485 {
486 #if PLATFORM(IOS_FAMILY)
487     static bool shouldRequireUserGestureToLoadVideo = dyld_get_program_sdk_version() >= DYLD_IOS_VERSION_10_0;
488     return shouldRequireUserGestureToLoadVideo;
489 #else
490     return false;
491 #endif
492 }
493
494 #if PLATFORM(MAC)
495 static uint32_t convertUserInterfaceDirectionPolicy(WKUserInterfaceDirectionPolicy policy)
496 {
497     switch (policy) {
498     case WKUserInterfaceDirectionPolicyContent:
499         return static_cast<uint32_t>(WebCore::UserInterfaceDirectionPolicy::Content);
500     case WKUserInterfaceDirectionPolicySystem:
501         return static_cast<uint32_t>(WebCore::UserInterfaceDirectionPolicy::System);
502     }
503     return static_cast<uint32_t>(WebCore::UserInterfaceDirectionPolicy::Content);
504 }
505
506 static uint32_t convertSystemLayoutDirection(NSUserInterfaceLayoutDirection direction)
507 {
508     switch (direction) {
509     case NSUserInterfaceLayoutDirectionLeftToRight:
510         return static_cast<uint32_t>(WebCore::UserInterfaceLayoutDirection::LTR);
511     case NSUserInterfaceLayoutDirectionRightToLeft:
512         return static_cast<uint32_t>(WebCore::UserInterfaceLayoutDirection::RTL);
513     }
514     return static_cast<uint32_t>(WebCore::UserInterfaceLayoutDirection::LTR);
515 }
516
517 #endif // PLATFORM(MAC)
518
519 static void validate(WKWebViewConfiguration *configuration)
520 {
521     if (!configuration.processPool)
522         [NSException raise:NSInvalidArgumentException format:@"configuration.processPool is nil"];
523     
524     if (!configuration.preferences)
525         [NSException raise:NSInvalidArgumentException format:@"configuration.preferences is nil"];
526     
527     if (!configuration.userContentController)
528         [NSException raise:NSInvalidArgumentException format:@"configuration.userContentController is nil"];
529     
530     if (!configuration.websiteDataStore)
531         [NSException raise:NSInvalidArgumentException format:@"configuration.websiteDataStore is nil"];
532     
533     if (!configuration._visitedLinkStore)
534         [NSException raise:NSInvalidArgumentException format:@"configuration._visitedLinkStore is nil"];
535     
536 #if PLATFORM(IOS_FAMILY)
537     if (!configuration._contentProviderRegistry)
538         [NSException raise:NSInvalidArgumentException format:@"configuration._contentProviderRegistry is nil"];
539 #endif
540 }
541
542 - (void)_initializeWithConfiguration:(WKWebViewConfiguration *)configuration
543 {
544     if (!configuration)
545         [NSException raise:NSInvalidArgumentException format:@"Configuration cannot be nil"];
546
547     _configuration = adoptNS([configuration copy]);
548
549     if (WKWebView *relatedWebView = [_configuration _relatedWebView]) {
550         WKProcessPool *processPool = [_configuration processPool];
551         WKProcessPool *relatedWebViewProcessPool = [relatedWebView->_configuration processPool];
552         if (processPool && processPool != relatedWebViewProcessPool)
553             [NSException raise:NSInvalidArgumentException format:@"Related web view %@ has process pool %@ but configuration specifies a different process pool %@", relatedWebView, relatedWebViewProcessPool, configuration.processPool];
554
555         [_configuration setProcessPool:relatedWebViewProcessPool];
556     }
557
558     validate(_configuration.get());
559
560     WebKit::WebProcessPool& processPool = *[_configuration processPool]->_processPool;
561     processPool.setResourceLoadStatisticsEnabled(configuration.websiteDataStore._resourceLoadStatisticsEnabled);
562
563     auto pageConfiguration = [configuration copyPageConfiguration];
564
565     pageConfiguration->setProcessPool(&processPool);
566     pageConfiguration->setPreferences([_configuration preferences]->_preferences.get());
567     if (WKWebView *relatedWebView = [_configuration _relatedWebView])
568         pageConfiguration->setRelatedPage(relatedWebView->_page.get());
569
570     pageConfiguration->setUserContentController([_configuration userContentController]->_userContentControllerProxy.get());
571     pageConfiguration->setVisitedLinkStore([_configuration _visitedLinkStore]->_visitedLinkStore.get());
572     pageConfiguration->setWebsiteDataStore([_configuration websiteDataStore]->_websiteDataStore.get());
573
574 #if PLATFORM(MAC)
575     if (auto pageGroup = WebKit::toImpl([configuration _pageGroup])) {
576         pageConfiguration->setPageGroup(pageGroup);
577         pageConfiguration->setUserContentController(&pageGroup->userContentController());
578     } else
579 #endif
580     {
581         NSString *groupIdentifier = configuration._groupIdentifier;
582         if (groupIdentifier.length)
583             pageConfiguration->setPageGroup(WebKit::WebPageGroup::create(configuration._groupIdentifier).ptr());
584     }
585
586     pageConfiguration->setAdditionalSupportedImageTypes(WebKit::webCoreStringVectorFromNSStringArray([_configuration _additionalSupportedImageTypes]));
587
588     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::suppressesIncrementalRenderingKey(), WebKit::WebPreferencesStore::Value(!![_configuration suppressesIncrementalRendering]));
589
590     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::shouldRespectImageOrientationKey(), WebKit::WebPreferencesStore::Value(!![_configuration _respectsImageOrientation]));
591     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::shouldPrintBackgroundsKey(), WebKit::WebPreferencesStore::Value(!![_configuration _printsBackgrounds]));
592     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::incrementalRenderingSuppressionTimeoutKey(), WebKit::WebPreferencesStore::Value([_configuration _incrementalRenderingSuppressionTimeout]));
593     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::javaScriptMarkupEnabledKey(), WebKit::WebPreferencesStore::Value(!![_configuration _allowsJavaScriptMarkup]));
594     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::shouldConvertPositionStyleOnCopyKey(), WebKit::WebPreferencesStore::Value(!![_configuration _convertsPositionStyleOnCopy]));
595     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::httpEquivEnabledKey(), WebKit::WebPreferencesStore::Value(!![_configuration _allowsMetaRefresh]));
596     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::allowUniversalAccessFromFileURLsKey(), WebKit::WebPreferencesStore::Value(!![_configuration _allowUniversalAccessFromFileURLs]));
597     pageConfiguration->setWaitsForPaintAfterViewDidMoveToWindow([_configuration _waitsForPaintAfterViewDidMoveToWindow]);
598     pageConfiguration->setDrawsBackground([_configuration _drawsBackground]);
599     pageConfiguration->setControlledByAutomation([_configuration _isControlledByAutomation]);
600     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::incompleteImageBorderEnabledKey(), WebKit::WebPreferencesStore::Value(!![_configuration _incompleteImageBorderEnabled]));
601     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::shouldDeferAsynchronousScriptsUntilAfterDocumentLoadKey(), WebKit::WebPreferencesStore::Value(!![_configuration _shouldDeferAsynchronousScriptsUntilAfterDocumentLoad]));
602
603 #if PLATFORM(MAC)
604     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::showsURLsInToolTipsEnabledKey(), WebKit::WebPreferencesStore::Value(!![_configuration _showsURLsInToolTips]));
605     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::serviceControlsEnabledKey(), WebKit::WebPreferencesStore::Value(!![_configuration _serviceControlsEnabled]));
606     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::imageControlsEnabledKey(), WebKit::WebPreferencesStore::Value(!![_configuration _imageControlsEnabled]));
607
608     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::userInterfaceDirectionPolicyKey(), WebKit::WebPreferencesStore::Value(convertUserInterfaceDirectionPolicy([_configuration userInterfaceDirectionPolicy])));
609     // We are in the View's initialization routine, so our client hasn't had time to set our user interface direction.
610     // Therefore, according to the docs[1], "this property contains the value reported by the app's userInterfaceLayoutDirection property."
611     // [1] http://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSView_Class/index.html#//apple_ref/doc/uid/20000014-SW222
612     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::systemLayoutDirectionKey(), WebKit::WebPreferencesStore::Value(convertSystemLayoutDirection(self.userInterfaceLayoutDirection)));
613 #endif
614
615 #if PLATFORM(IOS_FAMILY)
616     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::allowsInlineMediaPlaybackKey(), WebKit::WebPreferencesStore::Value(!![_configuration allowsInlineMediaPlayback]));
617     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::allowsInlineMediaPlaybackAfterFullscreenKey(), WebKit::WebPreferencesStore::Value(!![_configuration _allowsInlineMediaPlaybackAfterFullscreen]));
618     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::inlineMediaPlaybackRequiresPlaysInlineAttributeKey(), WebKit::WebPreferencesStore::Value(!![_configuration _inlineMediaPlaybackRequiresPlaysInlineAttribute]));
619     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::allowsPictureInPictureMediaPlaybackKey(), WebKit::WebPreferencesStore::Value(!![_configuration allowsPictureInPictureMediaPlayback] && shouldAllowPictureInPictureMediaPlayback()));
620     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::userInterfaceDirectionPolicyKey(), WebKit::WebPreferencesStore::Value(static_cast<uint32_t>(WebCore::UserInterfaceDirectionPolicy::Content)));
621     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::systemLayoutDirectionKey(), WebKit::WebPreferencesStore::Value(static_cast<uint32_t>(WebCore::TextDirection::LTR)));
622     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::allowSettingAnyXHRHeaderFromFileURLsKey(), WebKit::WebPreferencesStore::Value(shouldAllowSettingAnyXHRHeaderFromFileURLs()));
623 #if USE(SYSTEM_PREVIEW)
624     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::systemPreviewEnabledKey(), WebKit::WebPreferencesStore::Value(!![_configuration _systemPreviewEnabled]));
625 #endif
626 #endif
627
628     WKAudiovisualMediaTypes mediaTypesRequiringUserGesture = [_configuration mediaTypesRequiringUserActionForPlayback];
629     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::requiresUserGestureForVideoPlaybackKey(), WebKit::WebPreferencesStore::Value((mediaTypesRequiringUserGesture & WKAudiovisualMediaTypeVideo) == WKAudiovisualMediaTypeVideo));
630     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::requiresUserGestureForAudioPlaybackKey(), WebKit::WebPreferencesStore::Value(((mediaTypesRequiringUserGesture & WKAudiovisualMediaTypeAudio) == WKAudiovisualMediaTypeAudio)));
631     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::requiresUserGestureToLoadVideoKey(), WebKit::WebPreferencesStore::Value(shouldRequireUserGestureToLoadVideo()));
632     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::mainContentUserGestureOverrideEnabledKey(), WebKit::WebPreferencesStore::Value(!![_configuration _mainContentUserGestureOverrideEnabled]));
633     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::invisibleAutoplayNotPermittedKey(), WebKit::WebPreferencesStore::Value(!![_configuration _invisibleAutoplayNotPermitted]));
634     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::mediaDataLoadsAutomaticallyKey(), WebKit::WebPreferencesStore::Value(!![_configuration _mediaDataLoadsAutomatically]));
635     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::attachmentElementEnabledKey(), WebKit::WebPreferencesStore::Value(!![_configuration _attachmentElementEnabled]));
636
637 #if ENABLE(DATA_DETECTION) && PLATFORM(IOS_FAMILY)
638     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::dataDetectorTypesKey(), WebKit::WebPreferencesStore::Value(static_cast<uint32_t>(fromWKDataDetectorTypes([_configuration dataDetectorTypes]))));
639 #endif
640 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
641     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::allowsAirPlayForMediaPlaybackKey(), WebKit::WebPreferencesStore::Value(!![_configuration allowsAirPlayForMediaPlayback]));
642 #endif
643
644 #if ENABLE(APPLE_PAY)
645     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::applePayEnabledKey(), WebKit::WebPreferencesStore::Value(!![_configuration _applePayEnabled]));
646 #endif
647
648     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::needsStorageAccessFromFileURLsQuirkKey(), WebKit::WebPreferencesStore::Value(!![_configuration _needsStorageAccessFromFileURLsQuirk]));
649     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::mediaContentTypesRequiringHardwareSupportKey(), WebKit::WebPreferencesStore::Value(String([_configuration _mediaContentTypesRequiringHardwareSupport])));
650     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::allowMediaContentTypesRequiringHardwareSupportAsFallbackKey(), WebKit::WebPreferencesStore::Value(!![_configuration _allowMediaContentTypesRequiringHardwareSupportAsFallback]));
651
652     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::colorFilterEnabledKey(), WebKit::WebPreferencesStore::Value(!![_configuration _colorFilterEnabled]));
653
654     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::editableImagesEnabledKey(), WebKit::WebPreferencesStore::Value(!![_configuration _editableImagesEnabled]));
655     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::undoManagerAPIEnabledKey(), WebKit::WebPreferencesStore::Value(!![_configuration _undoManagerAPIEnabled]));
656
657 #if ENABLE(LEGACY_ENCRYPTED_MEDIA)
658     pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::legacyEncryptedMediaAPIEnabledKey(), WebKit::WebPreferencesStore::Value(!![_configuration _legacyEncryptedMediaAPIEnabled]));
659 #endif
660
661 #if PLATFORM(IOS_FAMILY) && ENABLE(SERVICE_WORKER)
662     if (!WTF::processHasEntitlement("com.apple.developer.WebKit.ServiceWorkers"))
663         pageConfiguration->preferenceValues().set(WebKit::WebPreferencesKey::serviceWorkersEnabledKey(), WebKit::WebPreferencesStore::Value(false));
664 #endif
665
666 #if PLATFORM(IOS_FAMILY)
667     CGRect bounds = self.bounds;
668     _scrollView = adoptNS([[WKScrollView alloc] initWithFrame:bounds]);
669     [_scrollView setInternalDelegate:self];
670     [_scrollView setBouncesZoom:YES];
671
672     if ([_configuration _editableImagesEnabled])
673         [_scrollView panGestureRecognizer].allowedTouchTypes = @[ @(UITouchTypeDirect) ];
674
675     _avoidsUnsafeArea = YES;
676     [self _updateScrollViewInsetAdjustmentBehavior];
677
678     [self addSubview:_scrollView.get()];
679
680     static uint32_t programSDKVersion = dyld_get_program_sdk_version();
681     _allowsLinkPreview = programSDKVersion >= firstSDKVersionWithLinkPreviewEnabledByDefault;
682
683     _contentView = adoptNS([[WKContentView alloc] initWithFrame:bounds processPool:processPool configuration:pageConfiguration.copyRef() webView:self]);
684
685     _page = [_contentView page];
686     [self _dispatchSetDeviceOrientation:deviceOrientation()];
687     _page->setDrawsBackground(self.opaque);
688
689     [_contentView layer].anchorPoint = CGPointZero;
690     [_contentView setFrame:bounds];
691     [_scrollView addSubview:_contentView.get()];
692     [_scrollView addSubview:[_contentView unscaledView]];
693     [self _updateScrollViewBackground];
694     _obscuredInsetEdgesAffectedBySafeArea = UIRectEdgeTop | UIRectEdgeLeft | UIRectEdgeRight;
695
696     _viewportMetaTagWidth = WebCore::ViewportArguments::ValueAuto;
697     _initialScaleFactor = 1;
698
699     if (NSNumber *enabledValue = [[NSUserDefaults standardUserDefaults] objectForKey:@"WebKitFastClickingDisabled"])
700         _fastClickingIsDisabled = enabledValue.boolValue;
701     else {
702 #if PLATFORM(WATCHOS)
703         _fastClickingIsDisabled = YES;
704 #else
705         _fastClickingIsDisabled = NO;
706 #endif
707     }
708
709     [self _frameOrBoundsChanged];
710
711     NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
712     [center addObserver:self selector:@selector(_keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];
713     [center addObserver:self selector:@selector(_keyboardDidChangeFrame:) name:UIKeyboardDidChangeFrameNotification object:nil];
714     [center addObserver:self selector:@selector(_keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
715     [center addObserver:self selector:@selector(_keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];
716     [center addObserver:self selector:@selector(_keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
717     [center addObserver:self selector:@selector(_windowDidRotate:) name:UIWindowDidRotateNotification object:nil];
718     [center addObserver:self selector:@selector(_contentSizeCategoryDidChange:) name:UIContentSizeCategoryDidChangeNotification object:nil];
719     _page->contentSizeCategoryDidChange([self _contentSizeCategory]);
720
721     [center addObserver:self selector:@selector(_accessibilitySettingsDidChange:) name:UIAccessibilityGrayscaleStatusDidChangeNotification object:nil];
722     [center addObserver:self selector:@selector(_accessibilitySettingsDidChange:) name:UIAccessibilityInvertColorsStatusDidChangeNotification object:nil];
723     [center addObserver:self selector:@selector(_accessibilitySettingsDidChange:) name:UIAccessibilityReduceMotionStatusDidChangeNotification object:nil];
724
725     [[_configuration _contentProviderRegistry] addPage:*_page];
726     _page->setForceAlwaysUserScalable([_configuration ignoresViewportScaleLimits]);
727
728     CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), (__bridge const void *)(self), hardwareKeyboardAvailabilityChangedCallback, (CFStringRef)[NSString stringWithUTF8String:kGSEventHardwareKeyboardAvailabilityChangedNotification], nullptr, CFNotificationSuspensionBehaviorCoalesce);
729 #endif
730
731 #if PLATFORM(MAC)
732     _impl = std::make_unique<WebKit::WebViewImpl>(self, self, processPool, pageConfiguration.copyRef());
733     _page = &_impl->page();
734
735     _impl->setAutomaticallyAdjustsContentInsets(true);
736     _impl->setRequiresUserActionForEditingControlsManager([configuration _requiresUserActionForEditingControlsManager]);
737 #endif
738
739 #if ENABLE(ACCESSIBILITY_EVENTS)
740     // Check _AXSWebAccessibilityEventsEnabled here to avoid compiler optimizing
741     // out the null check of kAXSWebAccessibilityEventsEnabledNotification.
742     if (!isNullFunctionPointer(_AXSWebAccessibilityEventsEnabled))
743         CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), (__bridge const void *)(self), accessibilityEventsEnabledChangedCallback, kAXSWebAccessibilityEventsEnabledNotification, 0, CFNotificationSuspensionBehaviorDeliverImmediately);
744     [self _updateAccessibilityEventsEnabled];
745 #endif
746
747     if (NSString *applicationNameForUserAgent = configuration.applicationNameForUserAgent)
748         _page->setApplicationNameForUserAgent(applicationNameForUserAgent);
749
750     _navigationState = std::make_unique<WebKit::NavigationState>(self);
751     _page->setNavigationClient(_navigationState->createNavigationClient());
752
753     _uiDelegate = std::make_unique<WebKit::UIDelegate>(self);
754     _page->setFindClient(std::make_unique<WebKit::FindClient>(self));
755     _page->setDiagnosticLoggingClient(std::make_unique<WebKit::DiagnosticLoggingClient>(self));
756
757     _iconLoadingDelegate = std::make_unique<WebKit::IconLoadingDelegate>(self);
758
759     [self _setUpSQLiteDatabaseTrackerClient];
760
761     for (auto& pair : pageConfiguration->urlSchemeHandlers())
762         _page->setURLSchemeHandlerForScheme(WebKit::WebURLSchemeHandlerCocoa::create(static_cast<WebKit::WebURLSchemeHandlerCocoa&>(pair.value.get()).apiHandler()), pair.key);
763
764     pageToViewMap().add(_page.get(), self);
765
766 #if PLATFORM(IOS_FAMILY)
767     _dragInteractionPolicy = _WKDragInteractionPolicyDefault;
768
769     _timeOfRequestForVisibleContentRectUpdate = MonotonicTime::now();
770     _timeOfLastVisibleContentRectUpdate = MonotonicTime::now();
771 #if PLATFORM(WATCHOS)
772     _allowsViewportShrinkToFit = YES;
773 #else
774     _allowsViewportShrinkToFit = NO;
775 #endif
776 #endif // PLATFORM(IOS_FAMILY)
777 }
778
779 - (void)_setUpSQLiteDatabaseTrackerClient
780 {
781 #if PLATFORM(IOS_FAMILY)
782     WebBackgroundTaskController *controller = [WebBackgroundTaskController sharedController];
783     if (controller.backgroundTaskStartBlock)
784         return;
785
786     controller.backgroundTaskStartBlock = ^NSUInteger (void (^expirationHandler)())
787     {
788         return [[UIApplication sharedApplication] beginBackgroundTaskWithName:@"com.apple.WebKit.DatabaseActivity" expirationHandler:expirationHandler];
789     };
790     controller.backgroundTaskEndBlock = ^(UIBackgroundTaskIdentifier taskIdentifier)
791     {
792         [[UIApplication sharedApplication] endBackgroundTask:taskIdentifier];
793     };
794     controller.invalidBackgroundTaskIdentifier = UIBackgroundTaskInvalid;
795
796     WebCore::SQLiteDatabaseTracker::setClient(&WebCore::WebSQLiteDatabaseTrackerClient::sharedWebSQLiteDatabaseTrackerClient());
797 #endif
798 }
799
800 - (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration
801 {
802     if (!(self = [super initWithFrame:frame]))
803         return nil;
804
805     [self _initializeWithConfiguration:configuration];
806
807     return self;
808 }
809
810 - (instancetype)initWithCoder:(NSCoder *)coder
811 {
812     if (!(self = [super initWithCoder:coder]))
813         return nil;
814
815     WKWebViewConfiguration *configuration = decodeObjectOfClassForKeyFromCoder([WKWebViewConfiguration class], @"configuration", coder);
816     [self _initializeWithConfiguration:configuration];
817
818     self.allowsBackForwardNavigationGestures = [coder decodeBoolForKey:@"allowsBackForwardNavigationGestures"];
819     self.customUserAgent = decodeObjectOfClassForKeyFromCoder([NSString class], @"customUserAgent", coder);
820     self.allowsLinkPreview = [coder decodeBoolForKey:@"allowsLinkPreview"];
821
822 #if PLATFORM(MAC)
823     self.allowsMagnification = [coder decodeBoolForKey:@"allowsMagnification"];
824     self.magnification = [coder decodeDoubleForKey:@"magnification"];
825 #endif
826
827     return self;
828 }
829
830 - (void)encodeWithCoder:(NSCoder *)coder
831 {
832     [super encodeWithCoder:coder];
833
834     [coder encodeObject:_configuration.get() forKey:@"configuration"];
835
836     [coder encodeBool:self.allowsBackForwardNavigationGestures forKey:@"allowsBackForwardNavigationGestures"];
837     [coder encodeObject:self.customUserAgent forKey:@"customUserAgent"];
838     [coder encodeBool:self.allowsLinkPreview forKey:@"allowsLinkPreview"];
839
840 #if PLATFORM(MAC)
841     [coder encodeBool:self.allowsMagnification forKey:@"allowsMagnification"];
842     [coder encodeDouble:self.magnification forKey:@"magnification"];
843 #endif
844 }
845
846 - (void)dealloc
847 {
848 #if PLATFORM(MAC)
849     [_textFinderClient willDestroyView:self];
850 #endif
851
852 #if PLATFORM(IOS_FAMILY)
853     [_contentView _webViewDestroyed];
854
855     if (_remoteObjectRegistry)
856         _page->process().processPool().removeMessageReceiver(Messages::RemoteObjectRegistry::messageReceiverName(), _page->pageID());
857 #endif
858
859     _page->close();
860
861 #if PLATFORM(IOS_FAMILY)
862     [_remoteObjectRegistry _invalidate];
863     [[_configuration _contentProviderRegistry] removePage:*_page];
864     [[NSNotificationCenter defaultCenter] removeObserver:self];
865     [_scrollView setInternalDelegate:nil];
866
867     CFNotificationCenterRemoveObserver(CFNotificationCenterGetDarwinNotifyCenter(), (__bridge const void *)(self), (CFStringRef)[NSString stringWithUTF8String:kGSEventHardwareKeyboardAvailabilityChangedNotification], nullptr);
868 #endif
869
870 #if ENABLE(ACCESSIBILITY_EVENTS)
871     CFNotificationCenterRemoveObserver(CFNotificationCenterGetDarwinNotifyCenter(), (__bridge const void *)(self), nullptr, nullptr);
872 #endif
873
874     pageToViewMap().remove(_page.get());
875
876     [super dealloc];
877 }
878
879 - (id)valueForUndefinedKey:(NSString *)key {
880     if ([key isEqualToString:@"serverTrust"])
881         return (__bridge id)[self serverTrust];
882
883     return [super valueForUndefinedKey:key];
884 }
885
886 - (WKWebViewConfiguration *)configuration
887 {
888     return [[_configuration copy] autorelease];
889 }
890
891 - (WKBackForwardList *)backForwardList
892 {
893     return wrapper(_page->backForwardList());
894 }
895
896 - (id <WKNavigationDelegate>)navigationDelegate
897 {
898     return _navigationState->navigationDelegate().autorelease();
899 }
900
901 - (void)setNavigationDelegate:(id <WKNavigationDelegate>)navigationDelegate
902 {
903     _page->setNavigationClient(_navigationState->createNavigationClient());
904     _navigationState->setNavigationDelegate(navigationDelegate);
905 }
906
907 - (id <WKUIDelegate>)UIDelegate
908 {
909     return _uiDelegate->delegate().autorelease();
910 }
911
912 - (void)setUIDelegate:(id<WKUIDelegate>)UIDelegate
913 {
914     _uiDelegate->setDelegate(UIDelegate);
915 #if ENABLE(CONTEXT_MENUS)
916     _page->setContextMenuClient(_uiDelegate->createContextMenuClient());
917 #endif
918     _page->setUIClient(_uiDelegate->createUIClient());
919 }
920
921 - (id <_WKIconLoadingDelegate>)_iconLoadingDelegate
922 {
923     return _iconLoadingDelegate->delegate().autorelease();
924 }
925
926 - (void)_setIconLoadingDelegate:(id<_WKIconLoadingDelegate>)iconLoadingDelegate
927 {
928     _page->setIconLoadingClient(_iconLoadingDelegate->createIconLoadingClient());
929     _iconLoadingDelegate->setDelegate(iconLoadingDelegate);
930 }
931
932 - (WKNavigation *)loadRequest:(NSURLRequest *)request
933 {
934     return wrapper(_page->loadRequest(request));
935 }
936
937 - (WKNavigation *)loadFileURL:(NSURL *)URL allowingReadAccessToURL:(NSURL *)readAccessURL
938 {
939     if (![URL isFileURL])
940         [NSException raise:NSInvalidArgumentException format:@"%@ is not a file URL", URL];
941
942     if (![readAccessURL isFileURL])
943         [NSException raise:NSInvalidArgumentException format:@"%@ is not a file URL", readAccessURL];
944
945     return wrapper(_page->loadFile([URL _web_originalDataAsWTFString], [readAccessURL _web_originalDataAsWTFString]));
946 }
947
948 - (WKNavigation *)loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL
949 {
950     NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
951
952     return [self loadData:data MIMEType:@"text/html" characterEncodingName:@"UTF-8" baseURL:baseURL];
953 }
954
955 - (WKNavigation *)loadData:(NSData *)data MIMEType:(NSString *)MIMEType characterEncodingName:(NSString *)characterEncodingName baseURL:(NSURL *)baseURL
956 {
957     return wrapper(_page->loadData({ static_cast<const uint8_t*>(data.bytes), data.length }, MIMEType, characterEncodingName, baseURL.absoluteString));
958 }
959
960 - (WKNavigation *)goToBackForwardListItem:(WKBackForwardListItem *)item
961 {
962     return wrapper(_page->goToBackForwardItem(item._item));
963 }
964
965 - (NSString *)title
966 {
967     return _page->pageLoadState().title();
968 }
969
970 - (NSURL *)URL
971 {
972     return [NSURL _web_URLWithWTFString:_page->pageLoadState().activeURL()];
973 }
974
975 - (BOOL)isLoading
976 {
977     return _page->pageLoadState().isLoading();
978 }
979
980 - (double)estimatedProgress
981 {
982     return _page->pageLoadState().estimatedProgress();
983 }
984
985 - (BOOL)hasOnlySecureContent
986 {
987     return _page->pageLoadState().hasOnlySecureContent();
988 }
989
990 - (SecTrustRef)serverTrust
991 {
992 #if HAVE(SEC_TRUST_SERIALIZATION)
993     auto certificateInfo = _page->pageLoadState().certificateInfo();
994     if (!certificateInfo)
995         return nil;
996
997     return certificateInfo->certificateInfo().trust();
998 #else
999     return nil;
1000 #endif
1001 }
1002
1003 - (BOOL)canGoBack
1004 {
1005     return _page->pageLoadState().canGoBack();
1006 }
1007
1008 - (BOOL)canGoForward
1009 {
1010     return _page->pageLoadState().canGoForward();
1011 }
1012
1013 - (WKNavigation *)goBack
1014 {
1015     if (self._safeBrowsingWarning)
1016         return [self reload];
1017     return wrapper(_page->goBack());
1018 }
1019
1020 - (WKNavigation *)goForward
1021 {
1022     return wrapper(_page->goForward());
1023 }
1024
1025 - (WKNavigation *)reload
1026 {
1027     OptionSet<WebCore::ReloadOption> reloadOptions;
1028     if (linkedOnOrAfter(WebKit::SDKVersion::FirstWithExpiredOnlyReloadBehavior))
1029         reloadOptions.add(WebCore::ReloadOption::ExpiredOnly);
1030
1031     return wrapper(_page->reload(reloadOptions));
1032 }
1033
1034 - (WKNavigation *)reloadFromOrigin
1035 {
1036     return wrapper(_page->reload(WebCore::ReloadOption::FromOrigin));
1037 }
1038
1039 - (void)stopLoading
1040 {
1041     _page->stopLoading();
1042 }
1043
1044 static WKErrorCode callbackErrorCode(WebKit::CallbackBase::Error error)
1045 {
1046     switch (error) {
1047     case WebKit::CallbackBase::Error::None:
1048         ASSERT_NOT_REACHED();
1049         return WKErrorUnknown;
1050
1051     case WebKit::CallbackBase::Error::Unknown:
1052         return WKErrorUnknown;
1053
1054     case WebKit::CallbackBase::Error::ProcessExited:
1055         return WKErrorWebContentProcessTerminated;
1056
1057     case WebKit::CallbackBase::Error::OwnerWasInvalidated:
1058         return WKErrorWebViewInvalidated;
1059     }
1060 }
1061
1062 - (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^)(id, NSError *))completionHandler
1063 {
1064     [self _evaluateJavaScript:javaScriptString forceUserGesture:YES completionHandler:completionHandler];
1065 }
1066
1067 - (void)_evaluateJavaScript:(NSString *)javaScriptString forceUserGesture:(BOOL)forceUserGesture completionHandler:(void (^)(id, NSError *))completionHandler
1068 {
1069     auto handler = adoptNS([completionHandler copy]);
1070
1071     _page->runJavaScriptInMainFrame(javaScriptString, forceUserGesture, [handler](API::SerializedScriptValue* serializedScriptValue, bool hadException, const WebCore::ExceptionDetails& details, WebKit::ScriptValueCallback::Error errorCode) {
1072         if (!handler)
1073             return;
1074
1075         if (errorCode != WebKit::ScriptValueCallback::Error::None) {
1076             auto error = createNSError(callbackErrorCode(errorCode));
1077             if (errorCode == WebKit::ScriptValueCallback::Error::OwnerWasInvalidated) {
1078                 // The OwnerWasInvalidated callback is synchronous. We don't want to call the block from within it
1079                 // because that can trigger re-entrancy bugs in WebKit.
1080                 // FIXME: It would be even better if GenericCallback did this for us.
1081                 dispatch_async(dispatch_get_main_queue(), [handler, error] {
1082                     auto rawHandler = (void (^)(id, NSError *))handler.get();
1083                     rawHandler(nil, error.get());
1084                 });
1085                 return;
1086             }
1087
1088             auto rawHandler = (void (^)(id, NSError *))handler.get();
1089             rawHandler(nil, error.get());
1090             return;
1091         }
1092
1093         auto rawHandler = (void (^)(id, NSError *))handler.get();
1094         if (hadException) {
1095             ASSERT(!serializedScriptValue);
1096
1097             RetainPtr<NSMutableDictionary> userInfo = adoptNS([[NSMutableDictionary alloc] init]);
1098
1099             [userInfo setObject:localizedDescriptionForErrorCode(WKErrorJavaScriptExceptionOccurred) forKey:NSLocalizedDescriptionKey];
1100             [userInfo setObject:static_cast<NSString *>(details.message) forKey:_WKJavaScriptExceptionMessageErrorKey];
1101             [userInfo setObject:@(details.lineNumber) forKey:_WKJavaScriptExceptionLineNumberErrorKey];
1102             [userInfo setObject:@(details.columnNumber) forKey:_WKJavaScriptExceptionColumnNumberErrorKey];
1103
1104             if (!details.sourceURL.isEmpty())
1105                 [userInfo setObject:[NSURL _web_URLWithWTFString:details.sourceURL] forKey:_WKJavaScriptExceptionSourceURLErrorKey];
1106
1107             rawHandler(nil, adoptNS([[NSError alloc] initWithDomain:WKErrorDomain code:WKErrorJavaScriptExceptionOccurred userInfo:userInfo.get()]).get());
1108             return;
1109         }
1110
1111         if (!serializedScriptValue) {
1112             rawHandler(nil, createNSError(WKErrorJavaScriptResultTypeIsUnsupported).get());
1113             return;
1114         }
1115
1116         id body = API::SerializedScriptValue::deserialize(serializedScriptValue->internalRepresentation(), 0);
1117         rawHandler(body, nil);
1118     });
1119 }
1120
1121 #if PLATFORM(MAC)
1122 - (void)takeSnapshotWithConfiguration:(WKSnapshotConfiguration *)snapshotConfiguration completionHandler:(void(^)(NSImage *, NSError *))completionHandler
1123 {
1124     CGRect rectInViewCoordinates = snapshotConfiguration && !CGRectIsNull(snapshotConfiguration.rect) ? snapshotConfiguration.rect : self.bounds;
1125     CGFloat snapshotWidth;
1126     if (snapshotConfiguration)
1127         snapshotWidth = snapshotConfiguration.snapshotWidth.doubleValue ?: rectInViewCoordinates.size.width;
1128     else
1129         snapshotWidth = self.bounds.size.width;
1130
1131     auto handler = makeBlockPtr(completionHandler);
1132     CGFloat imageScale = snapshotWidth / rectInViewCoordinates.size.width;
1133     CGFloat imageHeight = imageScale * rectInViewCoordinates.size.height;
1134
1135     // Need to scale by device scale factor or the image will be distorted.
1136     CGFloat deviceScale = _page->deviceScaleFactor();
1137     WebCore::IntSize bitmapSize(snapshotWidth, imageHeight);
1138     bitmapSize.scale(deviceScale, deviceScale);
1139
1140     // Software snapshot will not capture elements rendered with hardware acceleration (WebGL, video, etc).
1141     _page->takeSnapshot(WebCore::enclosingIntRect(rectInViewCoordinates), bitmapSize, WebKit::SnapshotOptionsInViewCoordinates, [handler, snapshotWidth, imageHeight](const WebKit::ShareableBitmap::Handle& imageHandle, WebKit::CallbackBase::Error errorCode) {
1142         if (errorCode != WebKit::ScriptValueCallback::Error::None) {
1143             auto error = createNSError(callbackErrorCode(errorCode));
1144             handler(nil, error.get());
1145             return;
1146         }
1147
1148         auto bitmap = WebKit::ShareableBitmap::create(imageHandle, WebKit::SharedMemory::Protection::ReadOnly);
1149         RetainPtr<CGImageRef> cgImage = bitmap ? bitmap->makeCGImage() : nullptr;
1150         RetainPtr<NSImage> nsImage = adoptNS([[NSImage alloc] initWithCGImage:cgImage.get() size:NSMakeSize(snapshotWidth, imageHeight)]);
1151         handler(nsImage.get(), nil);
1152     });
1153 }
1154
1155 #elif PLATFORM(IOS_FAMILY)
1156 - (void)takeSnapshotWithConfiguration:(WKSnapshotConfiguration *)snapshotConfiguration completionHandler:(void(^)(UIImage *, NSError *))completionHandler
1157 {
1158     CGRect rectInViewCoordinates = snapshotConfiguration && !CGRectIsNull(snapshotConfiguration.rect) ? snapshotConfiguration.rect : self.bounds;
1159     CGFloat snapshotWidth;
1160     if (snapshotConfiguration)
1161         snapshotWidth = snapshotConfiguration.snapshotWidth.doubleValue ?: rectInViewCoordinates.size.width;
1162     else
1163         snapshotWidth = self.bounds.size.width;
1164
1165     auto handler = makeBlockPtr(completionHandler);
1166     CGFloat deviceScale = _page->deviceScaleFactor();
1167
1168     [self _snapshotRect:rectInViewCoordinates intoImageOfWidth:(snapshotWidth * deviceScale) completionHandler:^(CGImageRef snapshotImage) {
1169         RetainPtr<NSError> error;
1170         RetainPtr<UIImage> uiImage;
1171
1172         if (!snapshotImage)
1173             error = createNSError(WKErrorUnknown);
1174         else
1175             uiImage = adoptNS([[UIImage alloc] initWithCGImage:snapshotImage scale:deviceScale orientation:UIImageOrientationUp]);
1176
1177         handler(uiImage.get(), error.get());
1178     }];
1179 }
1180 #endif
1181
1182 - (NSString *)customUserAgent
1183 {
1184     return _page->customUserAgent();
1185 }
1186
1187 - (void)setCustomUserAgent:(NSString *)customUserAgent
1188 {
1189     _page->setCustomUserAgent(customUserAgent);
1190 }
1191
1192 - (WKPageRef)_pageForTesting
1193 {
1194     return toAPI(_page.get());
1195 }
1196
1197 - (WebKit::WebPageProxy *)_page
1198 {
1199     return _page.get();
1200 }
1201
1202 - (BOOL)allowsLinkPreview
1203 {
1204 #if PLATFORM(MAC)
1205     return _impl->allowsLinkPreview();
1206 #elif PLATFORM(IOS_FAMILY)
1207     return _allowsLinkPreview;
1208 #endif
1209 }
1210
1211 - (void)setAllowsLinkPreview:(BOOL)allowsLinkPreview
1212 {
1213 #if PLATFORM(MAC)
1214     _impl->setAllowsLinkPreview(allowsLinkPreview);
1215     return;
1216 #elif PLATFORM(IOS_FAMILY)
1217     if (_allowsLinkPreview == allowsLinkPreview)
1218         return;
1219
1220     _allowsLinkPreview = allowsLinkPreview;
1221
1222 #if HAVE(LINK_PREVIEW)
1223     if (_allowsLinkPreview)
1224         [_contentView _registerPreview];
1225     else
1226         [_contentView _unregisterPreview];
1227 #endif // HAVE(LINK_PREVIEW)
1228 #endif // PLATFORM(IOS_FAMILY)
1229 }
1230
1231 - (CGSize)_viewportSizeForCSSViewportUnits
1232 {
1233     return _page->viewportSizeForCSSViewportUnits();
1234 }
1235
1236 - (void)_setViewportSizeForCSSViewportUnits:(CGSize)viewportSize
1237 {
1238     auto viewportSizeForViewportUnits = WebCore::IntSize(viewportSize);
1239     if (viewportSizeForViewportUnits.isEmpty())
1240         [NSException raise:NSInvalidArgumentException format:@"Viewport size should not be empty"];
1241
1242     _page->setViewportSizeForCSSViewportUnits(viewportSizeForViewportUnits);
1243 }
1244
1245 static NSTextAlignment nsTextAlignment(WebKit::TextAlignment alignment)
1246 {
1247     switch (alignment) {
1248     case WebKit::NoAlignment:
1249         return NSTextAlignmentNatural;
1250     case WebKit::LeftAlignment:
1251         return NSTextAlignmentLeft;
1252     case WebKit::RightAlignment:
1253         return NSTextAlignmentRight;
1254     case WebKit::CenterAlignment:
1255         return NSTextAlignmentCenter;
1256     case WebKit::JustifiedAlignment:
1257         return NSTextAlignmentJustified;
1258     }
1259     ASSERT_NOT_REACHED();
1260     return NSTextAlignmentNatural;
1261 }
1262
1263 static NSDictionary *dictionaryRepresentationForEditorState(const WebKit::EditorState& state)
1264 {
1265     if (state.isMissingPostLayoutData)
1266         return @{ @"post-layout-data" : @NO };
1267
1268     auto& postLayoutData = state.postLayoutData();
1269     return @{
1270         @"post-layout-data" : @YES,
1271         @"bold": postLayoutData.typingAttributes & WebKit::AttributeBold ? @YES : @NO,
1272         @"italic": postLayoutData.typingAttributes & WebKit::AttributeItalics ? @YES : @NO,
1273         @"underline": postLayoutData.typingAttributes & WebKit::AttributeUnderline ? @YES : @NO,
1274         @"text-alignment": @(nsTextAlignment(static_cast<WebKit::TextAlignment>(postLayoutData.textAlignment))),
1275         @"text-color": (NSString *)postLayoutData.textColor.cssText()
1276     };
1277 }
1278
1279 static _WKSelectionAttributes selectionAttributes(const WebKit::EditorState& editorState, _WKSelectionAttributes previousAttributes)
1280 {
1281     _WKSelectionAttributes attributes = _WKSelectionAttributeNoSelection;
1282     if (editorState.selectionIsNone)
1283         return attributes;
1284
1285     if (editorState.selectionIsRange)
1286         attributes |= _WKSelectionAttributeIsRange;
1287     else
1288         attributes |= _WKSelectionAttributeIsCaret;
1289
1290     if (!editorState.isMissingPostLayoutData) {
1291 #if PLATFORM(IOS_FAMILY)
1292         if (editorState.postLayoutData().atStartOfSentence)
1293             attributes |= _WKSelectionAttributeAtStartOfSentence;
1294 #endif
1295     } else if (previousAttributes & _WKSelectionAttributeAtStartOfSentence)
1296         attributes |= _WKSelectionAttributeAtStartOfSentence;
1297
1298     return attributes;
1299 }
1300
1301 - (void)_didChangeEditorState
1302 {
1303     auto newSelectionAttributes = selectionAttributes(_page->editorState(), _selectionAttributes);
1304     if (_selectionAttributes != newSelectionAttributes) {
1305         NSString *selectionAttributesKey = NSStringFromSelector(@selector(_selectionAttributes));
1306         [self willChangeValueForKey:selectionAttributesKey];
1307         _selectionAttributes = newSelectionAttributes;
1308         [self didChangeValueForKey:selectionAttributesKey];
1309     }
1310
1311     // FIXME: We should either rename -_webView:editorStateDidChange: to clarify that it's only intended for use when testing,
1312     // or remove it entirely and use -_webView:didChangeFontAttributes: instead once text alignment is supported in the set of
1313     // font attributes.
1314     id <WKUIDelegatePrivate> uiDelegate = (id <WKUIDelegatePrivate>)self.UIDelegate;
1315     if ([uiDelegate respondsToSelector:@selector(_webView:editorStateDidChange:)])
1316         [uiDelegate _webView:self editorStateDidChange:dictionaryRepresentationForEditorState(_page->editorState())];
1317 }
1318
1319 - (_WKSelectionAttributes)_selectionAttributes
1320 {
1321     return _selectionAttributes;
1322 }
1323
1324 - (void)_showSafeBrowsingWarning:(const WebKit::SafeBrowsingWarning&)warning completionHandler:(CompletionHandler<void(Variant<WebKit::ContinueUnsafeLoad, URL>&&)>&&)completionHandler
1325 {
1326     _safeBrowsingWarning = adoptNS([[WKSafeBrowsingWarning alloc] initWithFrame:self.bounds safeBrowsingWarning:warning completionHandler:[weakSelf = WeakObjCPtr<WKWebView>(self), completionHandler = WTFMove(completionHandler)] (auto&& result) mutable {
1327         completionHandler(WTFMove(result));
1328         auto strongSelf = weakSelf.get();
1329         if (!strongSelf)
1330             return;
1331         bool navigatesMainFrame = WTF::switchOn(result,
1332             [] (WebKit::ContinueUnsafeLoad continueUnsafeLoad) { return continueUnsafeLoad == WebKit::ContinueUnsafeLoad::Yes; },
1333             [] (const URL&) { return true; }
1334         );
1335         if (navigatesMainFrame && [strongSelf->_safeBrowsingWarning forMainFrameNavigation])
1336             return;
1337         [std::exchange(strongSelf->_safeBrowsingWarning, nullptr) removeFromSuperview];
1338     }]);
1339     [self addSubview:_safeBrowsingWarning.get()];
1340 }
1341
1342 - (void)_clearSafeBrowsingWarning
1343 {
1344     [std::exchange(_safeBrowsingWarning, nullptr) removeFromSuperview];
1345 }
1346
1347 - (void)_clearSafeBrowsingWarningIfForMainFrameNavigation
1348 {
1349     if ([_safeBrowsingWarning forMainFrameNavigation])
1350         [self _clearSafeBrowsingWarning];
1351 }
1352
1353 #if ENABLE(ATTACHMENT_ELEMENT)
1354
1355 - (void)_didInsertAttachment:(API::Attachment&)attachment withSource:(NSString *)source
1356 {
1357     id <WKUIDelegatePrivate> uiDelegate = (id <WKUIDelegatePrivate>)self.UIDelegate;
1358     if ([uiDelegate respondsToSelector:@selector(_webView:didInsertAttachment:withSource:)])
1359         [uiDelegate _webView:self didInsertAttachment:wrapper(attachment) withSource:source];
1360 }
1361
1362 - (void)_didRemoveAttachment:(API::Attachment&)attachment
1363 {
1364     id <WKUIDelegatePrivate> uiDelegate = (id <WKUIDelegatePrivate>)self.UIDelegate;
1365     if ([uiDelegate respondsToSelector:@selector(_webView:didRemoveAttachment:)])
1366         [uiDelegate _webView:self didRemoveAttachment:wrapper(attachment)];
1367 }
1368
1369 - (void)_didInvalidateDataForAttachment:(API::Attachment&)attachment
1370 {
1371     id <WKUIDelegatePrivate> uiDelegate = (id <WKUIDelegatePrivate>)self.UIDelegate;
1372     if ([uiDelegate respondsToSelector:@selector(_webView:didInvalidateDataForAttachment:)])
1373         [uiDelegate _webView:self didInvalidateDataForAttachment:wrapper(attachment)];
1374 }
1375
1376 #endif // ENABLE(ATTACHMENT_ELEMENT)
1377
1378 #pragma mark iOS-specific methods
1379
1380 #if PLATFORM(IOS_FAMILY)
1381
1382 - (BOOL)_contentViewIsFirstResponder
1383 {
1384     return self._currentContentView.isFirstResponder;
1385 }
1386
1387 - (_WKDragInteractionPolicy)_dragInteractionPolicy
1388 {
1389     return _dragInteractionPolicy;
1390 }
1391
1392 - (void)_setDragInteractionPolicy:(_WKDragInteractionPolicy)policy
1393 {
1394     if (_dragInteractionPolicy == policy)
1395         return;
1396
1397     _dragInteractionPolicy = policy;
1398 #if ENABLE(DRAG_SUPPORT)
1399     [_contentView _didChangeDragInteractionPolicy];
1400 #endif
1401 }
1402
1403 - (void)_populateArchivedSubviews:(NSMutableSet *)encodedViews
1404 {
1405     [super _populateArchivedSubviews:encodedViews];
1406
1407     if (_scrollView)
1408         [encodedViews removeObject:_scrollView.get()];
1409     if (_customContentFixedOverlayView)
1410         [encodedViews removeObject:_customContentFixedOverlayView.get()];
1411 }
1412
1413 - (BOOL)_isBackground
1414 {
1415     if ([self _isDisplayingPDF])
1416         return [_customContentView web_isBackground];
1417     return [_contentView isBackground];
1418 }
1419
1420 - (void)setFrame:(CGRect)frame
1421 {
1422     CGRect oldFrame = self.frame;
1423     [super setFrame:frame];
1424
1425     if (!CGSizeEqualToSize(oldFrame.size, frame.size))
1426         [self _frameOrBoundsChanged];
1427 }
1428
1429 - (void)setBounds:(CGRect)bounds
1430 {
1431     CGRect oldBounds = self.bounds;
1432     [super setBounds:bounds];
1433     [_customContentFixedOverlayView setFrame:self.bounds];
1434
1435     if (!CGSizeEqualToSize(oldBounds.size, bounds.size))
1436         [self _frameOrBoundsChanged];
1437 }
1438
1439 - (void)layoutSubviews
1440 {
1441     [_safeBrowsingWarning setFrame:self.bounds];
1442     [super layoutSubviews];
1443     [self _frameOrBoundsChanged];
1444 }
1445
1446 - (UIScrollView *)scrollView
1447 {
1448     return _scrollView.get();
1449 }
1450
1451 ALLOW_DEPRECATED_DECLARATIONS_BEGIN
1452 - (WKBrowsingContextController *)browsingContextController
1453 {
1454     return [_contentView browsingContextController];
1455 }
1456 ALLOW_DEPRECATED_DECLARATIONS_END
1457
1458 - (BOOL)becomeFirstResponder
1459 {
1460     UIView *currentContentView = self._currentContentView;
1461     if (currentContentView == _contentView && [_contentView superview])
1462         return [_contentView becomeFirstResponderForWebView] || [super becomeFirstResponder];
1463
1464     return [currentContentView becomeFirstResponder] || [super becomeFirstResponder];
1465 }
1466
1467 - (BOOL)canBecomeFirstResponder
1468 {
1469     if (self._currentContentView == _contentView)
1470         return [_contentView canBecomeFirstResponderForWebView];
1471
1472     return YES;
1473 }
1474
1475 - (BOOL)resignFirstResponder
1476 {
1477     if ([_contentView isFirstResponder])
1478         return [_contentView resignFirstResponderForWebView];
1479
1480     return [super resignFirstResponder];
1481 }
1482
1483 FOR_EACH_WKCONTENTVIEW_ACTION(FORWARD_ACTION_TO_WKCONTENTVIEW)
1484
1485 - (BOOL)canPerformAction:(SEL)action withSender:(id)sender
1486 {
1487     #define FORWARD_CANPERFORMACTION_TO_WKCONTENTVIEW(_action) \
1488         if (action == @selector(_action:)) \
1489             return self.usesStandardContentView && [_contentView canPerformActionForWebView:action withSender:sender];
1490
1491     FOR_EACH_WKCONTENTVIEW_ACTION(FORWARD_CANPERFORMACTION_TO_WKCONTENTVIEW)
1492     FOR_EACH_PRIVATE_WKCONTENTVIEW_ACTION(FORWARD_CANPERFORMACTION_TO_WKCONTENTVIEW)
1493     FORWARD_CANPERFORMACTION_TO_WKCONTENTVIEW(_setTextColor:sender)
1494     FORWARD_CANPERFORMACTION_TO_WKCONTENTVIEW(_setFontSize:sender)
1495     FORWARD_CANPERFORMACTION_TO_WKCONTENTVIEW(_setFont:sender)
1496
1497     #undef FORWARD_CANPERFORMACTION_TO_WKCONTENTVIEW
1498
1499     return [super canPerformAction:action withSender:sender];
1500 }
1501
1502 - (id)targetForAction:(SEL)action withSender:(id)sender
1503 {
1504     #define FORWARD_TARGETFORACTION_TO_WKCONTENTVIEW(_action) \
1505         if (action == @selector(_action:) && self.usesStandardContentView) \
1506             return [_contentView targetForActionForWebView:action withSender:sender];
1507
1508     FOR_EACH_WKCONTENTVIEW_ACTION(FORWARD_TARGETFORACTION_TO_WKCONTENTVIEW)
1509     FOR_EACH_PRIVATE_WKCONTENTVIEW_ACTION(FORWARD_TARGETFORACTION_TO_WKCONTENTVIEW)
1510     FORWARD_TARGETFORACTION_TO_WKCONTENTVIEW(_setTextColor:sender)
1511     FORWARD_TARGETFORACTION_TO_WKCONTENTVIEW(_setFontSize:sender)
1512     FORWARD_TARGETFORACTION_TO_WKCONTENTVIEW(_setFont:sender)
1513
1514     #undef FORWARD_TARGETFORACTION_TO_WKCONTENTVIEW
1515
1516     return [super targetForAction:action withSender:sender];
1517 }
1518
1519 static inline CGFloat floorToDevicePixel(CGFloat input, float deviceScaleFactor)
1520 {
1521     return CGFloor(input * deviceScaleFactor) / deviceScaleFactor;
1522 }
1523
1524 static inline bool pointsEqualInDevicePixels(CGPoint a, CGPoint b, float deviceScaleFactor)
1525 {
1526     return fabs(a.x * deviceScaleFactor - b.x * deviceScaleFactor) < std::numeric_limits<float>::epsilon()
1527         && fabs(a.y * deviceScaleFactor - b.y * deviceScaleFactor) < std::numeric_limits<float>::epsilon();
1528 }
1529
1530 static CGSize roundScrollViewContentSize(const WebKit::WebPageProxy& page, CGSize contentSize)
1531 {
1532     float deviceScaleFactor = page.deviceScaleFactor();
1533     return CGSizeMake(floorToDevicePixel(contentSize.width, deviceScaleFactor), floorToDevicePixel(contentSize.height, deviceScaleFactor));
1534 }
1535
1536 - (UIView *)_currentContentView
1537 {
1538     return _customContentView ? [_customContentView web_contentView] : _contentView.get();
1539 }
1540
1541 - (WKWebViewContentProviderRegistry *)_contentProviderRegistry
1542 {
1543     return [_configuration _contentProviderRegistry];
1544 }
1545
1546 - (WKSelectionGranularity)_selectionGranularity
1547 {
1548     return [_configuration selectionGranularity];
1549 }
1550
1551 - (void)_setHasCustomContentView:(BOOL)pageHasCustomContentView loadedMIMEType:(const WTF::String&)mimeType
1552 {
1553     if (pageHasCustomContentView) {
1554         [_customContentView removeFromSuperview];
1555         [_customContentFixedOverlayView removeFromSuperview];
1556
1557         Class representationClass = [[_configuration _contentProviderRegistry] providerForMIMEType:mimeType];
1558         ASSERT(representationClass);
1559         _customContentView = adoptNS([[representationClass alloc] web_initWithFrame:self.bounds webView:self mimeType:mimeType]);
1560         _customContentFixedOverlayView = adoptNS([[UIView alloc] initWithFrame:self.bounds]);
1561         [_customContentFixedOverlayView layer].name = @"CustomContentFixedOverlay";
1562         [_customContentFixedOverlayView setUserInteractionEnabled:NO];
1563
1564         [[_contentView unscaledView] removeFromSuperview];
1565         [_contentView removeFromSuperview];
1566         [_scrollView addSubview:_customContentView.get()];
1567         [self addSubview:_customContentFixedOverlayView.get()];
1568
1569         [_customContentView web_setMinimumSize:self.bounds.size];
1570         [_customContentView web_setFixedOverlayView:_customContentFixedOverlayView.get()];
1571
1572         _scrollViewBackgroundColor = WebCore::Color();
1573         [_scrollView setContentOffset:[self _initialContentOffsetForScrollView]];
1574
1575         [self _setAvoidsUnsafeArea:NO];
1576     } else if (_customContentView) {
1577         [_customContentView removeFromSuperview];
1578         _customContentView = nullptr;
1579
1580         [_customContentFixedOverlayView removeFromSuperview];
1581         _customContentFixedOverlayView = nullptr;
1582
1583         [_scrollView addSubview:_contentView.get()];
1584         [_scrollView addSubview:[_contentView unscaledView]];
1585         [_scrollView setContentSize:roundScrollViewContentSize(*_page, [_contentView frame].size)];
1586
1587         [_customContentFixedOverlayView setFrame:self.bounds];
1588         [self addSubview:_customContentFixedOverlayView.get()];
1589     }
1590
1591     if (self.isFirstResponder) {
1592         UIView *currentContentView = self._currentContentView;
1593         if (currentContentView == _contentView ? [_contentView canBecomeFirstResponderForWebView] : currentContentView.canBecomeFirstResponder)
1594             [currentContentView becomeFirstResponder];
1595     }
1596 }
1597
1598 - (void)_didFinishLoadingDataForCustomContentProviderWithSuggestedFilename:(const String&)suggestedFilename data:(NSData *)data
1599 {
1600     ASSERT(_customContentView);
1601     [_customContentView web_setContentProviderData:data suggestedFilename:suggestedFilename];
1602
1603     // FIXME: It may make more sense for custom content providers to invoke this when they're ready,
1604     // because there's no guarantee that all custom content providers will lay out synchronously.
1605     _page->didLayoutForCustomContentProvider();
1606 }
1607
1608 - (void)_handleKeyUIEvent:(::UIEvent *)event
1609 {
1610     // We only want to handle key events from the hardware keyboard when we are
1611     // first responder and a custom content view is installed; otherwise,
1612     // WKContentView will be the first responder and expects to get key events directly.
1613     if ([self isFirstResponder] && event._hidEvent) {
1614         if ([_customContentView respondsToSelector:@selector(web_handleKeyEvent:)]) {
1615             if ([_customContentView web_handleKeyEvent:event])
1616                 return;
1617         }
1618     }
1619
1620     [super _handleKeyUIEvent:event];
1621 }
1622
1623 - (void)_willInvokeUIScrollViewDelegateCallback
1624 {
1625     _delayUpdateVisibleContentRects = YES;
1626 }
1627
1628 - (void)_didInvokeUIScrollViewDelegateCallback
1629 {
1630     _delayUpdateVisibleContentRects = NO;
1631     if (_hadDelayedUpdateVisibleContentRects) {
1632         _hadDelayedUpdateVisibleContentRects = NO;
1633         [self _scheduleVisibleContentRectUpdate];
1634     }
1635 }
1636
1637 static CGFloat contentZoomScale(WKWebView *webView)
1638 {
1639     CGFloat scale = webView._currentContentView.layer.affineTransform.a;
1640     ASSERT(scale == [webView->_scrollView zoomScale]);
1641     return scale;
1642 }
1643
1644 static WebCore::Color baseScrollViewBackgroundColor(WKWebView *webView)
1645 {
1646     if (webView->_customContentView)
1647         return [webView->_customContentView backgroundColor].CGColor;
1648
1649     if (webView->_gestureController) {
1650         WebCore::Color color = webView->_gestureController->backgroundColorForCurrentSnapshot();
1651         if (color.isValid())
1652             return color;
1653     }
1654
1655     return webView->_page->pageExtendedBackgroundColor();
1656 }
1657
1658 static WebCore::Color scrollViewBackgroundColor(WKWebView *webView)
1659 {
1660     if (!webView.opaque)
1661         return WebCore::Color::transparent;
1662
1663     WebCore::Color color = baseScrollViewBackgroundColor(webView);
1664
1665     if (!color.isValid())
1666         color = WebCore::Color::white;
1667
1668     CGFloat zoomScale = contentZoomScale(webView);
1669     CGFloat minimumZoomScale = [webView->_scrollView minimumZoomScale];
1670     if (zoomScale < minimumZoomScale) {
1671         CGFloat slope = 12;
1672         CGFloat opacity = std::max<CGFloat>(1 - slope * (minimumZoomScale - zoomScale), 0);
1673         color = WebCore::colorWithOverrideAlpha(color.rgb(), opacity);
1674     }
1675
1676     return color;
1677 }
1678
1679 - (void)_updateScrollViewBackground
1680 {
1681     WebCore::Color color = scrollViewBackgroundColor(self);
1682
1683     if (_scrollViewBackgroundColor == color)
1684         return;
1685
1686     _scrollViewBackgroundColor = color;
1687
1688     auto uiBackgroundColor = adoptNS([[UIColor alloc] initWithCGColor:cachedCGColor(color)]);
1689     [_scrollView setBackgroundColor:uiBackgroundColor.get()];
1690
1691     // Update the indicator style based on the lightness/darkness of the background color.
1692     double hue, saturation, lightness;
1693     color.getHSL(hue, saturation, lightness);
1694     if (lightness <= .5 && color.isVisible())
1695         [_scrollView setIndicatorStyle:UIScrollViewIndicatorStyleWhite];
1696     else
1697         [_scrollView setIndicatorStyle:UIScrollViewIndicatorStyleDefault];
1698 }
1699
1700 - (void)_videoControlsManagerDidChange
1701 {
1702 #if ENABLE(FULLSCREEN_API)
1703     if (_fullScreenWindowController)
1704         [_fullScreenWindowController videoControlsManagerDidChange];
1705 #endif
1706 }
1707
1708 - (CGPoint)_initialContentOffsetForScrollView
1709 {
1710     auto combinedUnobscuredAndScrollViewInset = [self _computedContentInset];
1711     return CGPointMake(-combinedUnobscuredAndScrollViewInset.left, -combinedUnobscuredAndScrollViewInset.top);
1712 }
1713
1714 - (CGPoint)_contentOffsetAdjustedForObscuredInset:(CGPoint)point
1715 {
1716     CGPoint result = point;
1717     UIEdgeInsets contentInset = [self _computedObscuredInset];
1718
1719     result.x -= contentInset.left;
1720     result.y -= contentInset.top;
1721
1722     return result;
1723 }
1724
1725 - (UIRectEdge)_effectiveObscuredInsetEdgesAffectedBySafeArea
1726 {
1727     if (![self usesStandardContentView])
1728         return UIRectEdgeAll;
1729     return _obscuredInsetEdgesAffectedBySafeArea;
1730 }
1731
1732 - (UIEdgeInsets)_computedObscuredInset
1733 {
1734     if (!linkedOnOrAfter(WebKit::SDKVersion::FirstWhereScrollViewContentInsetsAreNotObscuringInsets)) {
1735         // For binary compability with third party apps, treat scroll view content insets as obscuring insets when the app is compiled
1736         // against a WebKit version without the fix in r229641.
1737         return [self _computedContentInset];
1738     }
1739
1740     if (_haveSetObscuredInsets)
1741         return _obscuredInsets;
1742
1743 #if PLATFORM(IOS)
1744     if (self._safeAreaShouldAffectObscuredInsets)
1745         return UIEdgeInsetsAdd(UIEdgeInsetsZero, self._scrollViewSystemContentInset, self._effectiveObscuredInsetEdgesAffectedBySafeArea);
1746 #endif
1747
1748     return UIEdgeInsetsZero;
1749 }
1750
1751 - (UIEdgeInsets)_computedContentInset
1752 {
1753     if (_haveSetObscuredInsets)
1754         return _obscuredInsets;
1755
1756     UIEdgeInsets insets = [_scrollView contentInset];
1757
1758 #if PLATFORM(IOS)
1759     if (self._safeAreaShouldAffectObscuredInsets)
1760         insets = UIEdgeInsetsAdd(insets, self._scrollViewSystemContentInset, self._effectiveObscuredInsetEdgesAffectedBySafeArea);
1761 #endif
1762
1763     return insets;
1764 }
1765
1766 - (UIEdgeInsets)_computedUnobscuredSafeAreaInset
1767 {
1768     if (_haveSetUnobscuredSafeAreaInsets)
1769         return _unobscuredSafeAreaInsets;
1770
1771 #if PLATFORM(IOS)
1772     if (!self._safeAreaShouldAffectObscuredInsets)
1773         return self.safeAreaInsets;
1774 #endif
1775
1776     return UIEdgeInsetsZero;
1777 }
1778
1779 - (void)_processWillSwapOrDidExit
1780 {
1781     // FIXME: Which ones of these need to be done in the process swap case and which ones in the exit case?
1782     [self _hidePasswordView];
1783     [self _cancelAnimatedResize];
1784
1785     _viewportMetaTagWidth = WebCore::ViewportArguments::ValueAuto;
1786     _initialScaleFactor = 1;
1787     _hasCommittedLoadForMainFrame = NO;
1788     _needsResetViewStateAfterCommitLoadForMainFrame = NO;
1789     _dynamicViewportUpdateMode = WebKit::DynamicViewportUpdateMode::NotResizing;
1790     _waitingForEndAnimatedResize = NO;
1791     _waitingForCommitAfterAnimatedResize = NO;
1792     _animatedResizeOriginalContentWidth = 0;
1793     [_contentView setHidden:NO];
1794     _scrollOffsetToRestore = WTF::nullopt;
1795     _unobscuredCenterToRestore = WTF::nullopt;
1796     _scrollViewBackgroundColor = WebCore::Color();
1797     _delayUpdateVisibleContentRects = NO;
1798     _hadDelayedUpdateVisibleContentRects = NO;
1799     _currentlyAdjustingScrollViewInsetsForKeyboard = NO;
1800     _lastSentViewLayoutSize = WTF::nullopt;
1801     _lastSentMaximumUnobscuredSize = WTF::nullopt;
1802     _lastSentDeviceOrientation = WTF::nullopt;
1803
1804     _frozenVisibleContentRect = WTF::nullopt;
1805     _frozenUnobscuredContentRect = WTF::nullopt;
1806
1807     _firstPaintAfterCommitLoadTransactionID = 0;
1808     _firstTransactionIDAfterPageRestore = WTF::nullopt;
1809
1810     _hasScheduledVisibleRectUpdate = NO;
1811     _commitDidRestoreScrollPosition = NO;
1812
1813     _avoidsUnsafeArea = YES;
1814 }
1815
1816 - (void)_processWillSwap
1817 {
1818     RELEASE_LOG_IF_ALLOWED("%p -[WKWebView _processWillSwap]", self);
1819     [self _processWillSwapOrDidExit];
1820 }
1821
1822 - (void)_processDidExit
1823 {
1824     RELEASE_LOG_IF_ALLOWED("%p -[WKWebView _processDidExit]", self);
1825
1826     [self _processWillSwapOrDidExit];
1827
1828     [_contentView setFrame:self.bounds];
1829     [_scrollView setBackgroundColor:[UIColor whiteColor]];
1830     [_scrollView setContentOffset:[self _initialContentOffsetForScrollView]];
1831     [_scrollView setZoomScale:1];
1832     
1833 }
1834
1835 - (void)_didRelaunchProcess
1836 {
1837     RELEASE_LOG_IF_ALLOWED("%p -[WKWebView _didRelaunchProcess]", self);
1838     _hasScheduledVisibleRectUpdate = NO;
1839     _visibleContentRectUpdateScheduledFromScrollViewInStableState = YES;
1840 }
1841
1842 - (void)_didCommitLoadForMainFrame
1843 {
1844     _firstPaintAfterCommitLoadTransactionID = downcast<WebKit::RemoteLayerTreeDrawingAreaProxy>(*_page->drawingArea()).nextLayerTreeTransactionID();
1845
1846     _hasCommittedLoadForMainFrame = YES;
1847     _needsResetViewStateAfterCommitLoadForMainFrame = YES;
1848
1849     [_scrollView _stopScrollingAndZoomingAnimations];
1850 }
1851
1852 static CGPoint contentOffsetBoundedInValidRange(UIScrollView *scrollView, CGPoint contentOffset)
1853 {
1854 #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000
1855     UIEdgeInsets contentInsets = scrollView.adjustedContentInset;
1856 #else
1857     UIEdgeInsets contentInsets = scrollView.contentInset;
1858 #endif
1859
1860     CGSize contentSize = scrollView.contentSize;
1861     CGSize scrollViewSize = scrollView.bounds.size;
1862
1863     CGPoint minimumContentOffset = CGPointMake(-contentInsets.left, -contentInsets.top);
1864     CGPoint maximumContentOffset = CGPointMake(std::max(minimumContentOffset.x, contentSize.width + contentInsets.right - scrollViewSize.width), std::max(minimumContentOffset.y, contentSize.height + contentInsets.bottom - scrollViewSize.height));
1865
1866     return CGPointMake(std::max(std::min(contentOffset.x, maximumContentOffset.x), minimumContentOffset.x), std::max(std::min(contentOffset.y, maximumContentOffset.y), minimumContentOffset.y));
1867 }
1868
1869 static void changeContentOffsetBoundedInValidRange(UIScrollView *scrollView, WebCore::FloatPoint contentOffset)
1870 {
1871     scrollView.contentOffset = contentOffsetBoundedInValidRange(scrollView, contentOffset);
1872 }
1873
1874 - (WebCore::FloatRect)visibleRectInViewCoordinates
1875 {
1876     WebCore::FloatRect bounds = self.bounds;
1877     bounds.moveBy([_scrollView contentOffset]);
1878     WebCore::FloatRect contentViewBounds = [_contentView bounds];
1879     bounds.intersect(contentViewBounds);
1880     return bounds;
1881 }
1882
1883 // WebCore stores the page scale factor as float instead of double. When we get a scale from WebCore,
1884 // we need to ignore differences that are within a small rounding error on floats.
1885 static inline bool areEssentiallyEqualAsFloat(float a, float b)
1886 {
1887     return WTF::areEssentiallyEqual(a, b);
1888 }
1889
1890 - (void)_didCommitLayerTreeDuringAnimatedResize:(const WebKit::RemoteLayerTreeTransaction&)layerTreeTransaction
1891 {
1892     auto updateID = layerTreeTransaction.dynamicViewportSizeUpdateID();
1893     if (updateID && *updateID == _currentDynamicViewportSizeUpdateID) {
1894         double pageScale = layerTreeTransaction.pageScaleFactor();
1895         WebCore::IntPoint scrollPosition = layerTreeTransaction.scrollPosition();
1896
1897         CGFloat animatingScaleTarget = [[_resizeAnimationView layer] transform].m11;
1898         double currentTargetScale = animatingScaleTarget * [[_contentView layer] transform].m11;
1899         double scale = pageScale / currentTargetScale;
1900         _resizeAnimationTransformAdjustments = CATransform3DMakeScale(scale, scale, 1);
1901
1902         CGPoint newContentOffset = [self _contentOffsetAdjustedForObscuredInset:CGPointMake(scrollPosition.x() * pageScale, scrollPosition.y() * pageScale)];
1903         CGPoint currentContentOffset = [_scrollView contentOffset];
1904
1905         _resizeAnimationTransformAdjustments.m41 = (currentContentOffset.x - newContentOffset.x) / animatingScaleTarget;
1906         _resizeAnimationTransformAdjustments.m42 = (currentContentOffset.y - newContentOffset.y) / animatingScaleTarget;
1907
1908         [_resizeAnimationView layer].sublayerTransform = _resizeAnimationTransformAdjustments;
1909
1910         // If we've already passed endAnimatedResize, immediately complete
1911         // the resize when we have an up-to-date layer tree. Otherwise,
1912         // we will defer completion until endAnimatedResize.
1913         _waitingForCommitAfterAnimatedResize = NO;
1914         if (!_waitingForEndAnimatedResize)
1915             [self _didCompleteAnimatedResize];
1916
1917         return;
1918     }
1919
1920     // If a commit arrives during the live part of a resize but before the
1921     // layer tree takes the current resize into account, it could change the
1922     // WKContentView's size. Update the resizeAnimationView's scale to ensure
1923     // we continue to fill the width of the resize target.
1924
1925     if (_waitingForEndAnimatedResize)
1926         return;
1927
1928     auto newViewLayoutSize = [self activeViewLayoutSize:self.bounds];
1929     CGFloat resizeAnimationViewScale = _animatedResizeOriginalContentWidth / newViewLayoutSize.width();
1930     [[_resizeAnimationView layer] setSublayerTransform:CATransform3DMakeScale(resizeAnimationViewScale, resizeAnimationViewScale, 1)];
1931 }
1932
1933 - (void)_didCommitLayerTree:(const WebKit::RemoteLayerTreeTransaction&)layerTreeTransaction
1934 {
1935     if (![self usesStandardContentView])
1936         return;
1937
1938     LOG_WITH_STREAM(VisibleRects, stream << "-[WKWebView " << _page->pageID() << " _didCommitLayerTree:] transactionID " <<  layerTreeTransaction.transactionID() << " _dynamicViewportUpdateMode " << (int)_dynamicViewportUpdateMode);
1939
1940     bool needUpdateVisibleContentRects = _page->updateLayoutViewportParameters(layerTreeTransaction);
1941
1942     if (_dynamicViewportUpdateMode != WebKit::DynamicViewportUpdateMode::NotResizing) {
1943         [self _didCommitLayerTreeDuringAnimatedResize:layerTreeTransaction];
1944         return;
1945     }
1946
1947     if (_resizeAnimationView)
1948         RELEASE_LOG_IF_ALLOWED("%p -[WKWebView _didCommitLayerTree:] - dynamicViewportUpdateMode is NotResizing, but still have a live resizeAnimationView (unpaired begin/endAnimatedResize?)", self);
1949
1950     CGSize newContentSize = roundScrollViewContentSize(*_page, [_contentView frame].size);
1951     [_scrollView _setContentSizePreservingContentOffsetDuringRubberband:newContentSize];
1952
1953     [_scrollView setMinimumZoomScale:layerTreeTransaction.minimumScaleFactor()];
1954     [_scrollView setMaximumZoomScale:layerTreeTransaction.maximumScaleFactor()];
1955     [_scrollView setZoomEnabled:layerTreeTransaction.allowsUserScaling()];
1956     if (!layerTreeTransaction.scaleWasSetByUIProcess() && ![_scrollView isZooming] && ![_scrollView isZoomBouncing] && ![_scrollView _isAnimatingZoom] && [_scrollView zoomScale] != layerTreeTransaction.pageScaleFactor()) {
1957         LOG_WITH_STREAM(VisibleRects, stream << " updating scroll view with pageScaleFactor " << layerTreeTransaction.pageScaleFactor());
1958         [_scrollView setZoomScale:layerTreeTransaction.pageScaleFactor()];
1959     }
1960
1961     _viewportMetaTagWidth = layerTreeTransaction.viewportMetaTagWidth();
1962     _viewportMetaTagWidthWasExplicit = layerTreeTransaction.viewportMetaTagWidthWasExplicit();
1963     _viewportMetaTagCameFromImageDocument = layerTreeTransaction.viewportMetaTagCameFromImageDocument();
1964     _initialScaleFactor = layerTreeTransaction.initialScaleFactor();
1965     if (_page->inStableState() && layerTreeTransaction.isInStableState() && [_stableStatePresentationUpdateCallbacks count]) {
1966         for (dispatch_block_t action in _stableStatePresentationUpdateCallbacks.get())
1967             action();
1968
1969         [_stableStatePresentationUpdateCallbacks removeAllObjects];
1970         _stableStatePresentationUpdateCallbacks = nil;
1971     }
1972
1973     if (![_contentView _mayDisableDoubleTapGesturesDuringSingleTap])
1974         [_contentView _setDoubleTapGesturesEnabled:self._allowsDoubleTapGestures];
1975
1976     [self _updateScrollViewBackground];
1977     [self _setAvoidsUnsafeArea:layerTreeTransaction.avoidsUnsafeArea()];
1978
1979     if (_gestureController)
1980         _gestureController->setRenderTreeSize(layerTreeTransaction.renderTreeSize());
1981
1982     if (_needsResetViewStateAfterCommitLoadForMainFrame && layerTreeTransaction.transactionID() >= _firstPaintAfterCommitLoadTransactionID) {
1983         _needsResetViewStateAfterCommitLoadForMainFrame = NO;
1984         [_scrollView setContentOffset:[self _initialContentOffsetForScrollView]];
1985         if (_observedRenderingProgressEvents & _WKRenderingProgressEventFirstPaint)
1986             _navigationState->didFirstPaint();
1987
1988         needUpdateVisibleContentRects = true;
1989     }
1990
1991     if (_firstTransactionIDAfterPageRestore && layerTreeTransaction.transactionID() >= _firstTransactionIDAfterPageRestore.value()) {
1992         if (_scrollOffsetToRestore) {
1993             WebCore::FloatPoint scaledScrollOffset = _scrollOffsetToRestore.value();
1994             _scrollOffsetToRestore = WTF::nullopt;
1995
1996             if (areEssentiallyEqualAsFloat(contentZoomScale(self), _scaleToRestore)) {
1997                 scaledScrollOffset.scale(_scaleToRestore);
1998                 WebCore::FloatPoint contentOffsetInScrollViewCoordinates = scaledScrollOffset - WebCore::FloatSize(_obscuredInsetsWhenSaved.left(), _obscuredInsetsWhenSaved.top());
1999
2000                 changeContentOffsetBoundedInValidRange(_scrollView.get(), contentOffsetInScrollViewCoordinates);
2001                 _commitDidRestoreScrollPosition = YES;
2002             }
2003
2004             needUpdateVisibleContentRects = true;
2005         }
2006
2007         if (_unobscuredCenterToRestore) {
2008             WebCore::FloatPoint unobscuredCenterToRestore = _unobscuredCenterToRestore.value();
2009             _unobscuredCenterToRestore = WTF::nullopt;
2010
2011             if (areEssentiallyEqualAsFloat(contentZoomScale(self), _scaleToRestore)) {
2012                 CGRect unobscuredRect = UIEdgeInsetsInsetRect(self.bounds, _obscuredInsets);
2013                 WebCore::FloatSize unobscuredContentSizeAtNewScale = WebCore::FloatSize(unobscuredRect.size) / _scaleToRestore;
2014                 WebCore::FloatPoint topLeftInDocumentCoordinates = unobscuredCenterToRestore - unobscuredContentSizeAtNewScale / 2;
2015
2016                 topLeftInDocumentCoordinates.scale(_scaleToRestore);
2017                 topLeftInDocumentCoordinates.moveBy(WebCore::FloatPoint(-_obscuredInsets.left, -_obscuredInsets.top));
2018
2019                 changeContentOffsetBoundedInValidRange(_scrollView.get(), topLeftInDocumentCoordinates);
2020             }
2021
2022             needUpdateVisibleContentRects = true;
2023         }
2024
2025         if (_gestureController)
2026             _gestureController->didRestoreScrollPosition();
2027
2028         _firstTransactionIDAfterPageRestore = WTF::nullopt;
2029     }
2030
2031     if (needUpdateVisibleContentRects)
2032         [self _scheduleVisibleContentRectUpdate];
2033
2034     if (WebKit::RemoteLayerTreeScrollingPerformanceData* scrollPerfData = _page->scrollingPerformanceData())
2035         scrollPerfData->didCommitLayerTree([self visibleRectInViewCoordinates]);
2036 }
2037
2038 - (void)_layerTreeCommitComplete
2039 {
2040     _commitDidRestoreScrollPosition = NO;
2041 }
2042
2043 - (void)_couldNotRestorePageState
2044 {
2045     // The gestureController may be waiting for the scroll position to be restored
2046     // in order to remove the swipe snapshot. Since the scroll position could not be
2047     // restored, tell the gestureController it was restored so that it no longer waits
2048     // for it.
2049     if (_gestureController)
2050         _gestureController->didRestoreScrollPosition();
2051 }
2052
2053 - (void)_restorePageScrollPosition:(Optional<WebCore::FloatPoint>)scrollPosition scrollOrigin:(WebCore::FloatPoint)scrollOrigin previousObscuredInset:(WebCore::FloatBoxExtent)obscuredInsets scale:(double)scale
2054 {
2055     if (_dynamicViewportUpdateMode != WebKit::DynamicViewportUpdateMode::NotResizing)
2056         return;
2057
2058     if (![self usesStandardContentView])
2059         return;
2060
2061     _firstTransactionIDAfterPageRestore = downcast<WebKit::RemoteLayerTreeDrawingAreaProxy>(*_page->drawingArea()).nextLayerTreeTransactionID();
2062     if (scrollPosition)
2063         _scrollOffsetToRestore = WebCore::ScrollableArea::scrollOffsetFromPosition(WebCore::FloatPoint(scrollPosition.value()), WebCore::toFloatSize(scrollOrigin));
2064     else
2065         _scrollOffsetToRestore = WTF::nullopt;
2066
2067     _obscuredInsetsWhenSaved = obscuredInsets;
2068     _scaleToRestore = scale;
2069 }
2070
2071 - (void)_restorePageStateToUnobscuredCenter:(Optional<WebCore::FloatPoint>)center scale:(double)scale
2072 {
2073     if (_dynamicViewportUpdateMode != WebKit::DynamicViewportUpdateMode::NotResizing)
2074         return;
2075
2076     if (![self usesStandardContentView])
2077         return;
2078
2079     _firstTransactionIDAfterPageRestore = downcast<WebKit::RemoteLayerTreeDrawingAreaProxy>(*_page->drawingArea()).nextLayerTreeTransactionID();
2080     _unobscuredCenterToRestore = center;
2081
2082     _scaleToRestore = scale;
2083 }
2084
2085 - (RefPtr<WebKit::ViewSnapshot>)_takeViewSnapshot
2086 {
2087 #if HAVE(CORE_ANIMATION_RENDER_SERVER)
2088     float deviceScale = WebCore::screenScaleFactor();
2089     WebCore::FloatSize snapshotSize(self.bounds.size);
2090     snapshotSize.scale(deviceScale);
2091
2092     CATransform3D transform = CATransform3DMakeScale(deviceScale, deviceScale, 1);
2093
2094 #if HAVE(IOSURFACE)
2095     WebCore::IOSurface::Format snapshotFormat = WebCore::screenSupportsExtendedColor() ? WebCore::IOSurface::Format::RGB10 : WebCore::IOSurface::Format::RGBA;
2096     auto surface = WebCore::IOSurface::create(WebCore::expandedIntSize(snapshotSize), WebCore::sRGBColorSpaceRef(), snapshotFormat);
2097     if (!surface)
2098         return nullptr;
2099     CARenderServerRenderLayerWithTransform(MACH_PORT_NULL, self.layer.context.contextId, reinterpret_cast<uint64_t>(self.layer), surface->surface(), 0, 0, &transform);
2100
2101 #if HAVE(IOSURFACE_ACCELERATOR)
2102     WebCore::IOSurface::Format compressedFormat = WebCore::IOSurface::Format::YUV422;
2103     if (WebCore::IOSurface::allowConversionFromFormatToFormat(snapshotFormat, compressedFormat)) {
2104         auto viewSnapshot = WebKit::ViewSnapshot::create(nullptr);
2105         WebCore::IOSurface::convertToFormat(WTFMove(surface), WebCore::IOSurface::Format::YUV422, [viewSnapshot = viewSnapshot.copyRef()](std::unique_ptr<WebCore::IOSurface> convertedSurface) {
2106             if (convertedSurface)
2107                 viewSnapshot->setSurface(WTFMove(convertedSurface));
2108         });
2109
2110         return viewSnapshot;
2111     }
2112 #endif // HAVE(IOSURFACE_ACCELERATOR)
2113
2114     return WebKit::ViewSnapshot::create(WTFMove(surface));
2115 #else // HAVE(IOSURFACE)
2116     uint32_t slotID = [WebKit::ViewSnapshotStore::snapshottingContext() createImageSlot:snapshotSize hasAlpha:YES];
2117
2118     if (!slotID)
2119         return nullptr;
2120
2121     CARenderServerCaptureLayerWithTransform(MACH_PORT_NULL, self.layer.context.contextId, (uint64_t)self.layer, slotID, 0, 0, &transform);
2122     WebCore::IntSize imageSize = WebCore::expandedIntSize(WebCore::FloatSize(snapshotSize));
2123     return WebKit::ViewSnapshot::create(slotID, imageSize, (imageSize.area() * 4).unsafeGet());
2124 #endif // HAVE(IOSURFACE)
2125 #else // HAVE(CORE_ANIMATION_RENDER_SERVER)
2126     return nullptr;
2127 #endif
2128 }
2129
2130 - (void)_zoomToPoint:(WebCore::FloatPoint)point atScale:(double)scale animated:(BOOL)animated
2131 {
2132     CFTimeInterval duration = 0;
2133     CGFloat zoomScale = contentZoomScale(self);
2134
2135     if (animated) {
2136         const double maximumZoomDuration = 0.4;
2137         const double minimumZoomDuration = 0.1;
2138         const double zoomDurationFactor = 0.3;
2139
2140         duration = std::min(fabs(log(zoomScale) - log(scale)) * zoomDurationFactor + minimumZoomDuration, maximumZoomDuration);
2141     }
2142
2143     if (scale != zoomScale)
2144         _page->willStartUserTriggeredZooming();
2145
2146     LOG_WITH_STREAM(VisibleRects, stream << "_zoomToPoint:" << point << " scale: " << scale << " duration:" << duration);
2147
2148     [_scrollView _zoomToCenter:point scale:scale duration:duration];
2149 }
2150
2151 - (void)_zoomToRect:(WebCore::FloatRect)targetRect atScale:(double)scale origin:(WebCore::FloatPoint)origin animated:(BOOL)animated
2152 {
2153     // FIXME: Some of this could be shared with _scrollToRect.
2154     const double visibleRectScaleChange = contentZoomScale(self) / scale;
2155     const WebCore::FloatRect visibleRect([self convertRect:self.bounds toView:self._currentContentView]);
2156     const WebCore::FloatRect unobscuredRect([self _contentRectForUserInteraction]);
2157
2158     const WebCore::FloatSize topLeftObscuredInsetAfterZoom((unobscuredRect.minXMinYCorner() - visibleRect.minXMinYCorner()) * visibleRectScaleChange);
2159     const WebCore::FloatSize bottomRightObscuredInsetAfterZoom((visibleRect.maxXMaxYCorner() - unobscuredRect.maxXMaxYCorner()) * visibleRectScaleChange);
2160
2161     const WebCore::FloatSize unobscuredRectSizeAfterZoom(unobscuredRect.size() * visibleRectScaleChange);
2162
2163     // Center to the target rect.
2164     WebCore::FloatPoint unobscuredRectLocationAfterZoom = targetRect.location() - (unobscuredRectSizeAfterZoom - targetRect.size()) * 0.5;
2165
2166     // Center to the tap point instead in case the target rect won't fit in a direction.
2167     if (targetRect.width() > unobscuredRectSizeAfterZoom.width())
2168         unobscuredRectLocationAfterZoom.setX(origin.x() - unobscuredRectSizeAfterZoom.width() / 2);
2169     if (targetRect.height() > unobscuredRectSizeAfterZoom.height())
2170         unobscuredRectLocationAfterZoom.setY(origin.y() - unobscuredRectSizeAfterZoom.height() / 2);
2171
2172     // We have computed where we want the unobscured rect to be. Now adjust for the obscuring insets.
2173     WebCore::FloatRect visibleRectAfterZoom(unobscuredRectLocationAfterZoom, unobscuredRectSizeAfterZoom);
2174     visibleRectAfterZoom.move(-topLeftObscuredInsetAfterZoom);
2175     visibleRectAfterZoom.expand(topLeftObscuredInsetAfterZoom + bottomRightObscuredInsetAfterZoom);
2176
2177     [self _zoomToPoint:visibleRectAfterZoom.center() atScale:scale animated:animated];
2178 }
2179
2180 static WebCore::FloatPoint constrainContentOffset(WebCore::FloatPoint contentOffset, WebCore::FloatSize contentSize, WebCore::FloatSize unobscuredContentSize)
2181 {
2182     WebCore::FloatSize maximumContentOffset = contentSize - unobscuredContentSize;
2183     return contentOffset.constrainedBetween(WebCore::FloatPoint(), WebCore::FloatPoint(maximumContentOffset));
2184 }
2185
2186 - (void)_scrollToContentScrollPosition:(WebCore::FloatPoint)scrollPosition scrollOrigin:(WebCore::IntPoint)scrollOrigin
2187 {
2188     if (_commitDidRestoreScrollPosition || _dynamicViewportUpdateMode != WebKit::DynamicViewportUpdateMode::NotResizing)
2189         return;
2190
2191     WebCore::FloatPoint contentOffset = WebCore::ScrollableArea::scrollOffsetFromPosition(scrollPosition, toFloatSize(scrollOrigin));
2192
2193     WebCore::FloatPoint scaledOffset = contentOffset;
2194     CGFloat zoomScale = contentZoomScale(self);
2195     scaledOffset.scale(zoomScale);
2196
2197     CGPoint contentOffsetInScrollViewCoordinates = [self _contentOffsetAdjustedForObscuredInset:scaledOffset];
2198     contentOffsetInScrollViewCoordinates = contentOffsetBoundedInValidRange(_scrollView.get(), contentOffsetInScrollViewCoordinates);
2199
2200     [_scrollView _stopScrollingAndZoomingAnimations];
2201
2202     if (!CGPointEqualToPoint(contentOffsetInScrollViewCoordinates, [_scrollView contentOffset]))
2203         [_scrollView setContentOffset:contentOffsetInScrollViewCoordinates];
2204     else {
2205         // If we haven't changed anything, there would not be any VisibleContentRect update sent to the content.
2206         // The WebProcess would keep the invalid contentOffset as its scroll position.
2207         // To synchronize the WebProcess with what is on screen, we send the VisibleContentRect again.
2208         _page->resendLastVisibleContentRects();
2209     }
2210 }
2211
2212 - (BOOL)_scrollToRect:(WebCore::FloatRect)targetRect origin:(WebCore::FloatPoint)origin minimumScrollDistance:(float)minimumScrollDistance
2213 {
2214     WebCore::FloatRect unobscuredContentRect([self _contentRectForUserInteraction]);
2215     WebCore::FloatPoint unobscuredContentOffset = unobscuredContentRect.location();
2216     WebCore::FloatSize contentSize([self._currentContentView bounds].size);
2217
2218     // Center the target rect in the scroll view.
2219     // If the target doesn't fit in the scroll view, center on the gesture location instead.
2220     WebCore::FloatPoint newUnobscuredContentOffset;
2221     if (targetRect.width() <= unobscuredContentRect.width())
2222         newUnobscuredContentOffset.setX(targetRect.x() - (unobscuredContentRect.width() - targetRect.width()) / 2);
2223     else
2224         newUnobscuredContentOffset.setX(origin.x() - unobscuredContentRect.width() / 2);
2225     if (targetRect.height() <= unobscuredContentRect.height())
2226         newUnobscuredContentOffset.setY(targetRect.y() - (unobscuredContentRect.height() - targetRect.height()) / 2);
2227     else
2228         newUnobscuredContentOffset.setY(origin.y() - unobscuredContentRect.height() / 2);
2229     newUnobscuredContentOffset = constrainContentOffset(newUnobscuredContentOffset, contentSize, unobscuredContentRect.size());
2230
2231     if (unobscuredContentOffset == newUnobscuredContentOffset) {
2232         if (targetRect.width() > unobscuredContentRect.width())
2233             newUnobscuredContentOffset.setX(origin.x() - unobscuredContentRect.width() / 2);
2234         if (targetRect.height() > unobscuredContentRect.height())
2235             newUnobscuredContentOffset.setY(origin.y() - unobscuredContentRect.height() / 2);
2236         newUnobscuredContentOffset = constrainContentOffset(newUnobscuredContentOffset, contentSize, unobscuredContentRect.size());
2237     }
2238
2239     WebCore::FloatSize scrollViewOffsetDelta = newUnobscuredContentOffset - unobscuredContentOffset;
2240     scrollViewOffsetDelta.scale(contentZoomScale(self));
2241
2242     float scrollDistance = scrollViewOffsetDelta.diagonalLength();
2243     if (scrollDistance < minimumScrollDistance)
2244         return false;
2245
2246     [_contentView willStartZoomOrScroll];
2247
2248     LOG_WITH_STREAM(VisibleRects, stream << "_scrollToRect: scrolling to " << [_scrollView contentOffset] + scrollViewOffsetDelta);
2249
2250     [_scrollView setContentOffset:([_scrollView contentOffset] + scrollViewOffsetDelta) animated:YES];
2251     return true;
2252 }
2253
2254 - (void)_zoomOutWithOrigin:(WebCore::FloatPoint)origin animated:(BOOL)animated
2255 {
2256     [self _zoomToPoint:origin atScale:[_scrollView minimumZoomScale] animated:animated];
2257 }
2258
2259 - (void)_zoomToInitialScaleWithOrigin:(WebCore::FloatPoint)origin animated:(BOOL)animated
2260 {
2261     ASSERT(_initialScaleFactor > 0);
2262     [self _zoomToPoint:origin atScale:_initialScaleFactor animated:animated];
2263 }
2264
2265 // focusedElementRect and selectionRect are both in document coordinates.
2266 - (void)_zoomToFocusRect:(const WebCore::FloatRect&)focusedElementRectInDocumentCoordinates selectionRect:(const WebCore::FloatRect&)selectionRectInDocumentCoordinates insideFixed:(BOOL)insideFixed
2267     fontSize:(float)fontSize minimumScale:(double)minimumScale maximumScale:(double)maximumScale allowScaling:(BOOL)allowScaling forceScroll:(BOOL)forceScroll
2268 {
2269     LOG_WITH_STREAM(VisibleRects, stream << "_zoomToFocusRect:" << focusedElementRectInDocumentCoordinates << " selectionRect:" << selectionRectInDocumentCoordinates);
2270     UNUSED_PARAM(insideFixed);
2271
2272     const double minimumHeightToShowContentAboveKeyboard = 106;
2273     const CFTimeInterval formControlZoomAnimationDuration = 0.25;
2274     const double caretOffsetFromWindowEdge = 8;
2275
2276     UIWindow *window = [_scrollView window];
2277
2278     // Find the portion of the view that is visible on the screen.
2279     UIViewController *topViewController = [[[_scrollView _viewControllerForAncestor] _rootAncestorViewController] _viewControllerForSupportedInterfaceOrientations];
2280     UIView *fullScreenView = topViewController.view;
2281     if (!fullScreenView)
2282         fullScreenView = window;
2283
2284     CGRect unobscuredScrollViewRectInWebViewCoordinates = UIEdgeInsetsInsetRect([self bounds], _obscuredInsets);
2285     CGRect visibleScrollViewBoundsInWebViewCoordinates = CGRectIntersection(unobscuredScrollViewRectInWebViewCoordinates, [fullScreenView convertRect:[fullScreenView bounds] toView:self]);
2286     CGRect formAssistantFrameInWebViewCoordinates = [window convertRect:_inputViewBounds toView:self];
2287     CGRect intersectionBetweenScrollViewAndFormAssistant = CGRectIntersection(visibleScrollViewBoundsInWebViewCoordinates, formAssistantFrameInWebViewCoordinates);
2288     CGSize visibleSize = visibleScrollViewBoundsInWebViewCoordinates.size;
2289
2290     CGFloat visibleOffsetFromTop = 0;
2291     if (!CGRectIsEmpty(intersectionBetweenScrollViewAndFormAssistant)) {
2292         CGFloat heightVisibleAboveFormAssistant = CGRectGetMinY(intersectionBetweenScrollViewAndFormAssistant) - CGRectGetMinY(visibleScrollViewBoundsInWebViewCoordinates);
2293         CGFloat heightVisibleBelowFormAssistant = CGRectGetMaxY(visibleScrollViewBoundsInWebViewCoordinates) - CGRectGetMaxY(intersectionBetweenScrollViewAndFormAssistant);
2294
2295         if (heightVisibleAboveFormAssistant >= minimumHeightToShowContentAboveKeyboard || heightVisibleBelowFormAssistant < heightVisibleAboveFormAssistant)
2296             visibleSize.height = heightVisibleAboveFormAssistant;
2297         else {
2298             visibleSize.height = heightVisibleBelowFormAssistant;
2299             visibleOffsetFromTop = CGRectGetMaxY(intersectionBetweenScrollViewAndFormAssistant) - CGRectGetMinY(visibleScrollViewBoundsInWebViewCoordinates);
2300         }
2301     }
2302
2303     // Zoom around the element's bounding frame. We use a "standard" size to determine the proper frame.
2304     double currentScale = contentZoomScale(self);
2305     double scale = currentScale;
2306     if (allowScaling) {
2307 #if PLATFORM(WATCHOS)
2308         const CGFloat minimumMarginForZoomingToEntireFocusRectInWebViewCoordinates = 10;
2309         const CGFloat maximumMarginForZoomingToEntireFocusRectInWebViewCoordinates = 35;
2310
2311         CGRect minimumTargetRectInDocumentCoordinates = UIRectInsetEdges(focusedElementRectInDocumentCoordinates, UIRectEdgeAll, -minimumMarginForZoomingToEntireFocusRectInWebViewCoordinates / currentScale);
2312         CGRect maximumTargetRectInDocumentCoordinates = UIRectInsetEdges(focusedElementRectInDocumentCoordinates, UIRectEdgeAll, -maximumMarginForZoomingToEntireFocusRectInWebViewCoordinates / currentScale);
2313
2314         double clampedMaximumTargetScale = clampTo<double>(std::min(visibleSize.width / CGRectGetWidth(minimumTargetRectInDocumentCoordinates), visibleSize.height / CGRectGetHeight(minimumTargetRectInDocumentCoordinates)), minimumScale, maximumScale);
2315         double clampedMinimumTargetScale = clampTo<double>(std::min(visibleSize.width / CGRectGetWidth(maximumTargetRectInDocumentCoordinates), visibleSize.height / CGRectGetHeight(maximumTargetRectInDocumentCoordinates)), minimumScale, maximumScale);
2316         scale = clampTo<double>(currentScale, clampedMinimumTargetScale, clampedMaximumTargetScale);
2317 #else
2318         const double webViewStandardFontSize = 16;
2319         scale = clampTo<double>(webViewStandardFontSize / fontSize, minimumScale, maximumScale);
2320 #endif
2321     }
2322
2323     CGFloat documentWidth = [_contentView bounds].size.width;
2324     scale = CGRound(documentWidth * scale) / documentWidth;
2325
2326     WebCore::FloatRect focusedElementRectInNewScale = focusedElementRectInDocumentCoordinates;
2327     focusedElementRectInNewScale.scale(scale);
2328     focusedElementRectInNewScale.moveBy([_contentView frame].origin);
2329
2330     BOOL selectionRectIsNotNull = !selectionRectInDocumentCoordinates.isZero();
2331     if (!forceScroll) {
2332         CGRect currentlyVisibleRegionInWebViewCoordinates;
2333         currentlyVisibleRegionInWebViewCoordinates.origin = unobscuredScrollViewRectInWebViewCoordinates.origin;
2334         currentlyVisibleRegionInWebViewCoordinates.origin.y += visibleOffsetFromTop;
2335         currentlyVisibleRegionInWebViewCoordinates.size = visibleSize;
2336
2337         // Don't bother scrolling if the entire node is already visible, whether or not we got a selectionRect.
2338         if (CGRectContainsRect(currentlyVisibleRegionInWebViewCoordinates, [self convertRect:focusedElementRectInDocumentCoordinates fromView:_contentView.get()]))
2339             return;
2340
2341         // Don't bother scrolling if we have a valid selectionRect and it is already visible.
2342         if (selectionRectIsNotNull && CGRectContainsRect(currentlyVisibleRegionInWebViewCoordinates, [self convertRect:selectionRectInDocumentCoordinates fromView:_contentView.get()]))
2343             return;
2344     }
2345
2346     // We want to center the focused element within the viewport, with as much spacing on all sides as
2347     // we can get based on the visible area after zooming. The spacing in either dimension is half the
2348     // difference between the size of the DOM node and the size of the visible frame.
2349     // If the element is too wide to be horizontally centered or too tall to be vertically centered, we
2350     // instead scroll such that the left edge or top edge of the element is within the left half or top
2351     // half of the viewport, respectively.
2352     CGFloat horizontalSpaceInWebViewCoordinates = (visibleSize.width - focusedElementRectInNewScale.width()) / 2.0;
2353     CGFloat verticalSpaceInWebViewCoordinates = (visibleSize.height - focusedElementRectInNewScale.height()) / 2.0;
2354
2355     auto topLeft = CGPointZero;
2356     auto scrollViewInsets = [_scrollView _effectiveContentInset];
2357     auto currentTopLeft = [_scrollView contentOffset];
2358
2359     if (_haveSetObscuredInsets) {
2360         currentTopLeft.x += _obscuredInsets.left;
2361         currentTopLeft.y += _obscuredInsets.top;
2362     }
2363
2364     if (horizontalSpaceInWebViewCoordinates > 0)
2365         topLeft.x = focusedElementRectInNewScale.x() - horizontalSpaceInWebViewCoordinates;
2366     else {
2367         auto minimumOffsetToRevealLeftEdge = std::max(-scrollViewInsets.left, focusedElementRectInNewScale.x() - visibleSize.width / 2);
2368         auto maximumOffsetToRevealLeftEdge = focusedElementRectInNewScale.x();
2369         topLeft.x = clampTo<double>(currentTopLeft.x, minimumOffsetToRevealLeftEdge, maximumOffsetToRevealLeftEdge);
2370     }
2371
2372     if (verticalSpaceInWebViewCoordinates > 0)
2373         topLeft.y = focusedElementRectInNewScale.y() - verticalSpaceInWebViewCoordinates;
2374     else {
2375         auto minimumOffsetToRevealTopEdge = std::max(-scrollViewInsets.top, focusedElementRectInNewScale.y() - visibleSize.height / 2);
2376         auto maximumOffsetToRevealTopEdge = focusedElementRectInNewScale.y();
2377         topLeft.y = clampTo<double>(currentTopLeft.y, minimumOffsetToRevealTopEdge, maximumOffsetToRevealTopEdge);
2378     }
2379
2380     topLeft.y -= visibleOffsetFromTop;
2381
2382     WebCore::FloatRect documentBoundsInNewScale = [_contentView bounds];
2383     documentBoundsInNewScale.scale(scale);
2384     documentBoundsInNewScale.moveBy([_contentView frame].origin);
2385
2386     CGFloat minimumAllowableHorizontalOffsetInWebViewCoordinates = -INFINITY;
2387     CGFloat minimumAllowableVerticalOffsetInWebViewCoordinates = -INFINITY;
2388     CGFloat maximumAllowableHorizontalOffsetInWebViewCoordinates = CGRectGetMaxX(documentBoundsInNewScale) - visibleSize.width;
2389     CGFloat maximumAllowableVerticalOffsetInWebViewCoordinates = CGRectGetMaxY(documentBoundsInNewScale) - visibleSize.height;
2390
2391     if (selectionRectIsNotNull) {
2392         WebCore::FloatRect selectionRectInNewScale = selectionRectInDocumentCoordinates;
2393         selectionRectInNewScale.scale(scale);
2394         selectionRectInNewScale.moveBy([_contentView frame].origin);
2395         // Adjust the min and max allowable scroll offsets, such that the selection rect remains visible.
2396         minimumAllowableHorizontalOffsetInWebViewCoordinates = CGRectGetMaxX(selectionRectInNewScale) + caretOffsetFromWindowEdge - visibleSize.width;
2397         minimumAllowableVerticalOffsetInWebViewCoordinates = CGRectGetMaxY(selectionRectInNewScale) + caretOffsetFromWindowEdge - visibleSize.height - visibleOffsetFromTop;
2398         maximumAllowableHorizontalOffsetInWebViewCoordinates = std::min<CGFloat>(maximumAllowableHorizontalOffsetInWebViewCoordinates, CGRectGetMinX(selectionRectInNewScale) - caretOffsetFromWindowEdge);
2399         maximumAllowableVerticalOffsetInWebViewCoordinates = std::min<CGFloat>(maximumAllowableVerticalOffsetInWebViewCoordinates, CGRectGetMinY(selectionRectInNewScale) - caretOffsetFromWindowEdge - visibleOffsetFromTop);
2400     }
2401
2402     // Constrain the left edge in document coordinates so that:
2403     //  - it isn't so small that the scrollVisibleRect isn't visible on the screen
2404     //  - it isn't so great that the document's right edge is less than the right edge of the screen
2405     topLeft.x = clampTo<CGFloat>(topLeft.x, minimumAllowableHorizontalOffsetInWebViewCoordinates, maximumAllowableHorizontalOffsetInWebViewCoordinates);
2406
2407     // Constrain the top edge in document coordinates so that:
2408     //  - it isn't so small that the scrollVisibleRect isn't visible on the screen
2409     //  - it isn't so great that the document's bottom edge is higher than the top of the form assistant
2410     topLeft.y = clampTo<CGFloat>(topLeft.y, minimumAllowableVerticalOffsetInWebViewCoordinates, maximumAllowableVerticalOffsetInWebViewCoordinates);
2411
2412     if (_haveSetObscuredInsets) {
2413         // This looks unintuitive, but is necessary in order to precisely center the focused element in the visible area.
2414         // The top left position already accounts for top and left obscured insets - i.e., a topLeft of (0, 0) corresponds
2415         // to the top- and left-most point below (and to the right of) the top inset area and left inset areas, respectively.
2416         // However, when telling WKScrollView to scroll to a given center position, this center position is computed relative
2417         // to the coordinate space of the scroll view. Thus, to compute our center position from the top left position, we
2418         // need to first move the top left position up and to the left, and then add half the width and height of the content
2419         // area (including obscured insets).
2420         topLeft.x -= _obscuredInsets.left;
2421         topLeft.y -= _obscuredInsets.top;
2422     }
2423
2424     WebCore::FloatPoint newCenter = CGPointMake(topLeft.x + CGRectGetWidth(self.bounds) / 2, topLeft.y + CGRectGetHeight(self.bounds) / 2);
2425
2426     if (scale != currentScale)
2427         _page->willStartUserTriggeredZooming();
2428
2429     LOG_WITH_STREAM(VisibleRects, stream << "_zoomToFocusRect: zooming to " << newCenter << " scale:" << scale);
2430
2431     // The newCenter has been computed in the new scale, but _zoomToCenter expected the center to be in the original scale.
2432     newCenter.scale(1 / scale);
2433     [_scrollView _zoomToCenter:newCenter scale:scale duration:formControlZoomAnimationDuration force:YES];
2434 }
2435
2436 - (CGFloat)_targetContentZoomScaleForRect:(const WebCore::FloatRect&)targetRect currentScale:(double)currentScale fitEntireRect:(BOOL)fitEntireRect minimumScale:(double)minimumScale maximumScale:(double)maximumScale
2437 {
2438     WebCore::FloatSize unobscuredContentSize([self _contentRectForUserInteraction].size);
2439     double horizontalScale = unobscuredContentSize.width() * currentScale / targetRect.width();
2440     double verticalScale = unobscuredContentSize.height() * currentScale / targetRect.height();
2441
2442     horizontalScale = std::min(std::max(horizontalScale, minimumScale), maximumScale);
2443     verticalScale = std::min(std::max(verticalScale, minimumScale), maximumScale);
2444
2445     return fitEntireRect ? std::min(horizontalScale, verticalScale) : horizontalScale;
2446 }
2447
2448 - (BOOL)_zoomToRect:(WebCore::FloatRect)targetRect withOrigin:(WebCore::FloatPoint)origin fitEntireRect:(BOOL)fitEntireRect minimumScale:(double)minimumScale maximumScale:(double)maximumScale minimumScrollDistance:(float)minimumScrollDistance
2449 {
2450     const float maximumScaleFactorDeltaForPanScroll = 0.02;
2451
2452     double currentScale = contentZoomScale(self);
2453     double targetScale = [self _targetContentZoomScaleForRect:targetRect currentScale:currentScale fitEntireRect:fitEntireRect minimumScale:minimumScale maximumScale:maximumScale];
2454
2455     if (fabs(targetScale - currentScale) < maximumScaleFactorDeltaForPanScroll) {
2456         if ([self _scrollToRect:targetRect origin:origin minimumScrollDistance:minimumScrollDistance])
2457             return true;
2458     } else if (targetScale != currentScale) {
2459         [self _zoomToRect:targetRect atScale:targetScale origin:origin animated:YES];
2460         return true;
2461     }
2462
2463     return false;
2464 }
2465
2466 - (void)didMoveToWindow
2467 {
2468     _page->activityStateDidChange(WebCore::ActivityState::allFlags());
2469 }
2470
2471 - (void)setOpaque:(BOOL)opaque
2472 {
2473     BOOL oldOpaque = self.opaque;
2474
2475     [super setOpaque:opaque];
2476     [_contentView setOpaque:opaque];
2477
2478     if (oldOpaque == opaque)
2479         return;
2480
2481     if (!_page)
2482         return;
2483
2484     _page->setDrawsBackground(opaque);
2485     [self _updateScrollViewBackground];
2486 }
2487
2488 - (void)setBackgroundColor:(UIColor *)backgroundColor
2489 {
2490     [super setBackgroundColor:backgroundColor];
2491     [_contentView setBackgroundColor:backgroundColor];
2492 }
2493
2494 - (BOOL)_allowsDoubleTapGestures
2495 {
2496     if (_fastClickingIsDisabled)
2497         return YES;
2498
2499     // If the page is not user scalable, we don't allow double tap gestures.
2500     if (![_scrollView isZoomEnabled] || [_scrollView minimumZoomScale] >= [_scrollView maximumZoomScale])
2501         return NO;
2502
2503     // If the viewport width was not explicit, we allow double tap gestures.
2504     if (!_viewportMetaTagWidthWasExplicit || _viewportMetaTagCameFromImageDocument)
2505         return YES;
2506
2507     // If the page set a viewport width that wasn't the device width, then it was
2508     // scaled and thus will probably need to zoom.
2509     if (_viewportMetaTagWidth != WebCore::ViewportArguments::ValueDeviceWidth)
2510         return YES;
2511
2512     // At this point, we have a page that asked for width = device-width. However,
2513     // if the content's width and height were large, we might have had to shrink it.
2514     // We'll enable double tap zoom whenever we're not at the actual initial scale.
2515     return !areEssentiallyEqualAsFloat(contentZoomScale(self), _initialScaleFactor);
2516 }
2517
2518 - (BOOL)_stylusTapGestureShouldCreateEditableImage
2519 {
2520     return [_configuration _editableImagesEnabled];
2521 }
2522
2523 #pragma mark - UIScrollViewDelegate
2524
2525 - (BOOL)usesStandardContentView
2526 {
2527     return !_customContentView && !_passwordView;
2528 }
2529
2530 - (CGSize)scrollView:(UIScrollView*)scrollView contentSizeForZoomScale:(CGFloat)scale withProposedSize:(CGSize)proposedSize
2531 {
2532     return roundScrollViewContentSize(*_page, proposedSize);
2533 }
2534
2535 - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
2536 {
2537     ASSERT(_scrollView == scrollView);
2538     return self._currentContentView;
2539 }
2540
2541 - (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view
2542 {
2543     if (![self usesStandardContentView]) {
2544         if ([_customContentView respondsToSelector:@selector(web_scrollViewWillBeginZooming:withView:)])
2545             [_customContentView web_scrollViewWillBeginZooming:scrollView withView:view];
2546         return;
2547     }
2548
2549     if (scrollView.pinchGestureRecognizer.state == UIGestureRecognizerStateBegan) {
2550         _page->willStartUserTriggeredZooming();
2551         [_contentView scrollViewWillStartPanOrPinchGesture];
2552     }
2553     [_contentView willStartZoomOrScroll];
2554
2555 #if ENABLE(POINTER_EVENTS)
2556     [_contentView cancelPointersForGestureRecognizer:scrollView.pinchGestureRecognizer];
2557 #endif
2558 }
2559
2560 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
2561 {
2562     if (![self usesStandardContentView])
2563         return;
2564
2565     if (scrollView.panGestureRecognizer.state == UIGestureRecognizerStateBegan)
2566         [_contentView scrollViewWillStartPanOrPinchGesture];
2567
2568     [_contentView willStartZoomOrScroll];
2569 #if ENABLE(CSS_SCROLL_SNAP) && ENABLE(ASYNC_SCROLLING)
2570     // FIXME: We will want to detect whether snapping will occur before beginning to drag. See WebPageProxy::didCommitLayerTree.
2571     WebKit::RemoteScrollingCoordinatorProxy* coordinator = _page->scrollingCoordinatorProxy();
2572     ASSERT(scrollView == _scrollView.get());
2573     CGFloat scrollDecelerationFactor = (coordinator && coordinator->shouldSetScrollViewDecelerationRateFast()) ? UIScrollViewDecelerationRateFast : UIScrollViewDecelerationRateNormal;
2574     scrollView.horizontalScrollDecelerationFactor = scrollDecelerationFactor;
2575     scrollView.verticalScrollDecelerationFactor = scrollDecelerationFactor;
2576 #endif
2577 }
2578
2579 - (void)_didFinishScrolling
2580 {
2581     if (![self usesStandardContentView])
2582         return;
2583
2584     [self _scheduleVisibleContentRectUpdate];
2585     [_contentView didFinishScrolling];
2586 }
2587
2588 - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
2589 {
2590     // Work around <rdar://problem/16374753> by avoiding deceleration while
2591     // zooming. We'll animate to the right place once the zoom finishes.
2592     if ([scrollView isZooming])
2593         *targetContentOffset = [scrollView contentOffset];
2594 #if ENABLE(POINTER_EVENTS)
2595     else {
2596         if ([_contentView preventsPanningInXAxis])
2597             targetContentOffset->x = scrollView.contentOffset.x;
2598         if ([_contentView preventsPanningInYAxis])
2599             targetContentOffset->y = scrollView.contentOffset.y;
2600     }
2601 #endif
2602 #if ENABLE(CSS_SCROLL_SNAP) && ENABLE(ASYNC_SCROLLING)
2603     if (WebKit::RemoteScrollingCoordinatorProxy* coordinator = _page->scrollingCoordinatorProxy()) {
2604         // FIXME: Here, I'm finding the maximum horizontal/vertical scroll offsets. There's probably a better way to do this.
2605         CGSize maxScrollOffsets = CGSizeMake(scrollView.contentSize.width - scrollView.bounds.size.width, scrollView.contentSize.height - scrollView.bounds.size.height);
2606
2607         UIEdgeInsets obscuredInset;
2608
2609         id<WKUIDelegatePrivate> uiDelegatePrivate = static_cast<id <WKUIDelegatePrivate>>([self UIDelegate]);
2610         if ([uiDelegatePrivate respondsToSelector:@selector(_webView:finalObscuredInsetsForScrollView:withVelocity:targetContentOffset:)])
2611             obscuredInset = [uiDelegatePrivate _webView:self finalObscuredInsetsForScrollView:scrollView withVelocity:velocity targetContentOffset:targetContentOffset];
2612         else
2613             obscuredInset = [self _computedObscuredInset];
2614
2615         CGRect unobscuredRect = UIEdgeInsetsInsetRect(self.bounds, obscuredInset);
2616
2617         coordinator->adjustTargetContentOffsetForSnapping(maxScrollOffsets, velocity, unobscuredRect.origin.y, targetContentOffset);
2618     }
2619 #endif
2620 }
2621
2622 - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
2623 {
2624     // If we're decelerating, scroll offset will be updated when scrollViewDidFinishDecelerating: is called.
2625     if (!decelerate)
2626         [self _didFinishScrolling];
2627 }
2628
2629 - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
2630 {
2631     [self _didFinishScrolling];
2632 }
2633
2634 - (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView
2635 {
2636     [self _didFinishScrolling];
2637 }
2638
2639 #if ENABLE(POINTER_EVENTS)
2640 - (CGPoint)_scrollView:(UIScrollView *)scrollView adjustedOffsetForOffset:(CGPoint)offset translation:(CGPoint)translation startPoint:(CGPoint)start locationInView:(CGPoint)locationInView horizontalVelocity:(inout double *)hv verticalVelocity:(inout double *)vv
2641 {
2642     if (![_contentView preventsPanningInXAxis] && ![_contentView preventsPanningInYAxis]) {
2643         [_contentView cancelPointersForGestureRecognizer:scrollView.panGestureRecognizer];
2644         return offset;
2645     }
2646
2647     CGPoint adjustedContentOffset = CGPointMake(offset.x, offset.y);
2648     if ([_contentView preventsPanningInXAxis])
2649         adjustedContentOffset.x = start.x;
2650     if ([_contentView preventsPanningInYAxis])
2651         adjustedContentOffset.y = start.y;
2652
2653     if ((![_contentView preventsPanningInXAxis] && adjustedContentOffset.x != start.x)
2654         || (![_contentView preventsPanningInYAxis] && adjustedContentOffset.y != start.y)) {
2655         [_contentView cancelPointersForGestureRecognizer:scrollView.panGestureRecognizer];
2656     }
2657
2658     return adjustedContentOffset;
2659 }
2660 #endif
2661
2662 - (void)scrollViewDidScroll:(UIScrollView *)scrollView
2663 {
2664     if (![self usesStandardContentView] && [_customContentView respondsToSelector:@selector(web_scrollViewDidScroll:)])
2665         [_customContentView web_scrollViewDidScroll:(UIScrollView *)scrollView];
2666
2667     [self _scheduleVisibleContentRectUpdateAfterScrollInView:scrollView];
2668
2669     if (WebKit::RemoteLayerTreeScrollingPerformanceData* scrollPerfData = _page->scrollingPerformanceData())
2670         scrollPerfData->didScroll([self visibleRectInViewCoordinates]);
2671 }
2672
2673 - (void)scrollViewDidZoom:(UIScrollView *)scrollView
2674 {
2675     if (![self usesStandardContentView] && [_customContentView respondsToSelector:@selector(web_scrollViewDidZoom:)])
2676         [_customContentView web_scrollViewDidZoom:scrollView];
2677
2678     [self _updateScrollViewBackground];
2679     [self _scheduleVisibleContentRectUpdateAfterScrollInView:scrollView];
2680 }
2681
2682 - (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale
2683 {
2684     if (![self usesStandardContentView] && [_customContentView respondsToSelector:@selector(web_scrollViewDidEndZooming:withView:atScale:)])
2685         [_customContentView web_scrollViewDidEndZooming:scrollView withView:view atScale:scale];
2686
2687     ASSERT(scrollView == _scrollView);
2688     // FIXME: remove when rdar://problem/36065495 is fixed.
2689     // When rotating with two fingers down, UIScrollView can set a bogus content view position.
2690     // "Center" is top left because we set the anchorPoint to 0,0.
2691     [_contentView setCenter:self.bounds.origin];
2692
2693     [self _scheduleVisibleContentRectUpdateAfterScrollInView:scrollView];
2694     [_contentView didZoomToScale:scale];
2695 }
2696
2697 - (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
2698 {
2699     [self _didFinishScrolling];
2700 }
2701
2702 - (void)_scrollViewDidInterruptDecelerating:(UIScrollView *)scrollView
2703 {
2704     if (![self usesStandardContentView])
2705         return;
2706
2707     [_contentView didInterruptScrolling];
2708     [self _scheduleVisibleContentRectUpdateAfterScrollInView:scrollView];
2709 }
2710
2711 - (UIView *)_enclosingViewForExposedRectComputation
2712 {
2713     return [self _scroller];
2714 }
2715
2716 - (CGRect)_visibleRectInEnclosingView:(UIView *)enclosingView
2717 {
2718     if (!enclosingView)
2719         return self.bounds;
2720
2721     CGRect exposedRect = [enclosingView convertRect:enclosingView.bounds toView:self];
2722     return CGRectIntersectsRect(exposedRect, self.bounds) ? CGRectIntersection(exposedRect, self.bounds) : CGRectZero;
2723 }
2724
2725 - (CGRect)_visibleContentRect
2726 {
2727     if (_frozenVisibleContentRect)
2728         return _frozenVisibleContentRect.value();
2729
2730     CGRect visibleRectInContentCoordinates = [self convertRect:self.bounds toView:_contentView.get()];
2731
2732     if (UIView *enclosingView = [self _enclosingViewForExposedRectComputation]) {
2733         CGRect viewVisibleRect = [self _visibleRectInEnclosingView:enclosingView];
2734         CGRect viewVisibleContentRect = [self convertRect:viewVisibleRect toView:_contentView.get()];
2735         visibleRectInContentCoordinates = CGRectIntersection(visibleRectInContentCoordinates, viewVisibleContentRect);
2736     }
2737
2738     return visibleRectInContentCoordinates;
2739 }
2740
2741 // Called when some ancestor UIScrollView scrolls.
2742 - (void)_didScroll
2743 {
2744     [self _scheduleVisibleContentRectUpdateAfterScrollInView:[self _scroller]];
2745
2746     const NSTimeInterval ScrollingEndedTimerInterval = 0.032;
2747     if (!_enclosingScrollViewScrollTimer) {
2748         _enclosingScrollViewScrollTimer = adoptNS([[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:ScrollingEndedTimerInterval]
2749             interval:0 target:self selector:@selector(_enclosingScrollerScrollingEnded:) userInfo:nil repeats:YES]);
2750         [[NSRunLoop mainRunLoop] addTimer:_enclosingScrollViewScrollTimer.get() forMode:NSDefaultRunLoopMode];
2751     }
2752     _didScrollSinceLastTimerFire = YES;
2753 }
2754
2755 - (void)_enclosingScrollerScrollingEnded:(NSTimer *)timer
2756 {
2757     if (_didScrollSinceLastTimerFire) {
2758         _didScrollSinceLastTimerFire = NO;
2759         return;
2760     }
2761
2762     [self _scheduleVisibleContentRectUpdate];
2763     [_enclosingScrollViewScrollTimer invalidate];
2764     _enclosingScrollViewScrollTimer = nil;
2765 }
2766
2767 - (UIEdgeInsets)_scrollViewSystemContentInset
2768 {
2769     // It's not safe to access the scroll view's safeAreaInsets or _systemContentInset from
2770     // inside our layoutSubviews implementation, because they aren't updated until afterwards.
2771     // Instead, depend on the fact that the UIScrollView and WKWebView are in the same coordinate
2772     // space, and map the WKWebView's own insets into the scroll view manually.
2773     return UIEdgeInsetsAdd([_scrollView _contentScrollInset], self.safeAreaInsets, [_scrollView _edgesApplyingSafeAreaInsetsToContentInset]);
2774 }
2775
2776 - (WebCore::FloatSize)activeViewLayoutSize:(const CGRect&)bounds
2777 {
2778     if (_overridesViewLayoutSize)
2779         return WebCore::FloatSize(_viewLayoutSizeOverride);
2780
2781 #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000
2782     return WebCore::FloatSize(UIEdgeInsetsInsetRect(CGRectMake(0, 0, bounds.size.width, bounds.size.height), self._scrollViewSystemContentInset).size);
2783 #else
2784     return WebCore::FloatSize { bounds.size };
2785 #endif
2786 }
2787
2788 - (void)_dispatchSetViewLayoutSize:(WebCore::FloatSize)viewLayoutSize
2789 {
2790     if (_lastSentViewLayoutSize && CGSizeEqualToSize(_lastSentViewLayoutSize.value(), viewLayoutSize))
2791         return;
2792
2793     LOG_WITH_STREAM(VisibleRects, stream << "-[WKWebView " << _page->pageID() << " _dispatchSetViewLayoutSize:] " << viewLayoutSize << " contentZoomScale " << contentZoomScale(self));
2794     _page->setViewportConfigurationViewLayoutSize(viewLayoutSize, _page->layoutSizeScaleFactor(), _minimumEffectiveDeviceWidth);
2795     _lastSentViewLayoutSize = viewLayoutSize;
2796 }
2797
2798 - (void)_dispatchSetMaximumUnobscuredSize:(WebCore::FloatSize)maximumUnobscuredSize
2799 {
2800     if (_lastSentMaximumUnobscuredSize && CGSizeEqualToSize(_lastSentMaximumUnobscuredSize.value(), maximumUnobscuredSize))
2801         return;
2802
2803     _page->setMaximumUnobscuredSize(maximumUnobscuredSize);
2804     _lastSentMaximumUnobscuredSize = maximumUnobscuredSize;
2805 }
2806
2807 - (void)_dispatchSetDeviceOrientation:(int32_t)deviceOrientation
2808 {
2809     if (_lastSentDeviceOrientation && _lastSentDeviceOrientation.value() == deviceOrientation)
2810         return;
2811
2812     _page->setDeviceOrientation(deviceOrientation);
2813     _lastSentDeviceOrientation = deviceOrientation;
2814 }
2815
2816 - (void)_frameOrBoundsChanged
2817 {
2818     CGRect bounds = self.bounds;
2819     [_scrollView setFrame:bounds];
2820
2821     if (_dynamicViewportUpdateMode == WebKit::DynamicViewportUpdateMode::NotResizing) {
2822         if (!_overridesViewLayoutSize)
2823             [self _dispatchSetViewLayoutSize:[self activeViewLayoutSize:self.bounds]];
2824         if (!_overridesMaximumUnobscuredSize)
2825             [self _dispatchSetMaximumUnobscuredSize:WebCore::FloatSize(bounds.size)];
2826
2827         BOOL sizeChanged = NO;
2828         if (auto drawingArea = _page->drawingArea())
2829             sizeChanged = drawingArea->setSize(WebCore::IntSize(bounds.size));
2830
2831         if (sizeChanged & [self usesStandardContentView])
2832             [_contentView setSizeChangedSinceLastVisibleContentRectUpdate:YES];
2833     }
2834
2835     [_customContentView web_setMinimumSize:bounds.size];
2836     [self _scheduleVisibleContentRectUpdate];
2837 }
2838
2839 // 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.
2840 - (CGRect)_contentRectForUserInteraction
2841 {
2842     // FIXME: handle split keyboard.
2843     UIEdgeInsets obscuredInsets = _obscuredInsets;
2844     obscuredInsets.bottom = std::max(_obscuredInsets.bottom, _inputViewBounds.size.height);
2845     CGRect unobscuredRect = UIEdgeInsetsInsetRect(self.bounds, obscuredInsets);
2846     return [self convertRect:unobscuredRect toView:self._currentContentView];
2847 }
2848
2849 // Ideally UIScrollView would expose this for us: <rdar://problem/21394567>.
2850 - (BOOL)_scrollViewIsRubberBanding
2851 {
2852     float deviceScaleFactor = _page->deviceScaleFactor();
2853
2854     CGPoint contentOffset = [_scrollView contentOffset];
2855     CGPoint boundedOffset = contentOffsetBoundedInValidRange(_scrollView.get(), contentOffset);
2856     return !pointsEqualInDevicePixels(contentOffset, boundedOffset, deviceScaleFactor);
2857 }
2858
2859 #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000
2860 - (void)safeAreaInsetsDidChange
2861 {
2862     [super safeAreaInsetsDidChange];
2863
2864     [self _scheduleVisibleContentRectUpdate];
2865 }
2866 #endif
2867
2868 - (void)_scheduleVisibleContentRectUpdate
2869 {
2870     // For visible rect updates not associated with a specific UIScrollView, just consider our own scroller.
2871     [self _scheduleVisibleContentRectUpdateAfterScrollInView:_scrollView.get()];
2872 }
2873
2874 - (BOOL)_scrollViewIsInStableState:(UIScrollView *)scrollView
2875 {
2876     BOOL isStableState = !([scrollView isDragging] || [scrollView isDecelerating] || [scrollView isZooming] || [scrollView _isAnimatingZoom] || [scrollView _isScrollingToTop]);
2877
2878     if (isStableState && scrollView == _scrollView.get())
2879         isStableState = !_isChangingObscuredInsetsInteractively;
2880
2881     if (isStableState && scrollView == _scrollView.get())
2882         isStableState = ![self _scrollViewIsRubberBanding];
2883
2884     if (isStableState)
2885         isStableState = !scrollView._isInterruptingDeceleration;
2886
2887     if (NSNumber *stableOverride = self._stableStateOverride)
2888         isStableState = stableOverride.boolValue;
2889
2890     return isStableState;
2891 }
2892
2893 - (void)_addUpdateVisibleContentRectPreCommitHandler
2894 {
2895     auto retainedSelf = retainPtr(self);
2896     [CATransaction addCommitHandler:[retainedSelf] {
2897         WKWebView *webView = retainedSelf.get();
2898         if (![webView _isValid]) {
2899             RELEASE_LOG_IF(webView._page && webView._page->isAlwaysOnLoggingAllowed(), ViewState, "In CATransaction preCommitHandler, WKWebView %p is invalid", webView);
2900             return;
2901         }
2902
2903         @try {
2904             [webView _updateVisibleContentRects];
2905         } @catch (NSException *exception) {
2906             RELEASE_LOG_IF(webView._page && webView._page->isAlwaysOnLoggingAllowed(), ViewState, "In CATransaction preCommitHandler, -[WKWebView %p _updateVisibleContentRects] threw an exception", webView);
2907         }
2908         webView->_hasScheduledVisibleRectUpdate = NO;
2909     } forPhase:kCATransactionPhasePreCommit];
2910 }
2911
2912 - (void)_scheduleVisibleContentRectUpdateAfterScrollInView:(UIScrollView *)scrollView
2913 {
2914     _visibleContentRectUpdateScheduledFromScrollViewInStableState = [self _scrollViewIsInStableState:scrollView];
2915
2916     if (_hasScheduledVisibleRectUpdate) {
2917         auto timeNow = MonotonicTime::now();
2918         if ((timeNow - _timeOfRequestForVisibleContentRectUpdate) > delayBeforeNoVisibleContentsRectsLogging) {
2919             RELEASE_LOG_IF_ALLOWED("-[WKWebView %p _scheduleVisibleContentRectUpdateAfterScrollInView]: _hasScheduledVisibleRectUpdate is true but haven't updated visible content rects for %.2fs (last update was %.2fs ago) - valid %d",
2920                 self, (timeNow - _timeOfRequestForVisibleContentRectUpdate).value(), (timeNow - _timeOfLastVisibleContentRectUpdate).value(), [self _isValid]);
2921         }
2922         return;
2923     }
2924
2925     _hasScheduledVisibleRectUpdate = YES;
2926     _timeOfRequestForVisibleContentRectUpdate = MonotonicTime::now();
2927
2928     CATransactionPhase transactionPhase = [CATransaction currentPhase];
2929     if (transactionPhase == kCATransactionPhaseNull || transactionPhase == kCATransactionPhasePreLayout) {
2930         [self _addUpdateVisibleContentRectPreCommitHandler];
2931         return;
2932     }
2933
2934     dispatch_async(dispatch_get_main_queue(), [retainedSelf = retainPtr(self)] {
2935         WKWebView *webView = retainedSelf.get();
2936         if (![webView _isValid])
2937             return;
2938         [webView _addUpdateVisibleContentRectPreCommitHandler];
2939     });
2940 }
2941
2942 static bool scrollViewCanScroll(UIScrollView *scrollView)
2943 {
2944     if (!scrollView)
2945         return NO;
2946
2947     UIEdgeInsets contentInset = scrollView.contentInset;
2948     CGSize contentSize = scrollView.contentSize;
2949     CGSize boundsSize = scrollView.bounds.size;
2950
2951     return (contentSize.width + contentInset.left + contentInset.right) > boundsSize.width
2952         || (contentSize.height + contentInset.top + contentInset.bottom) > boundsSize.height;
2953 }
2954
2955 - (CGRect)_contentBoundsExtendedForRubberbandingWithScale:(CGFloat)scaleFactor
2956 {
2957     CGPoint contentOffset = [_scrollView contentOffset];
2958     CGPoint boundedOffset = contentOffsetBoundedInValidRange(_scrollView.get(), contentOffset);
2959
2960     CGFloat horiontalRubberbandAmountInContentCoordinates = (contentOffset.x - boundedOffset.x) / scaleFactor;
2961     CGFloat verticalRubberbandAmountInContentCoordinates = (contentOffset.y - boundedOffset.y) / scaleFactor;
2962
2963     CGRect extendedBounds = [_contentView bounds];
2964
2965     if (horiontalRubberbandAmountInContentCoordinates < 0) {
2966         extendedBounds.origin.x += horiontalRubberbandAmountInContentCoordinates;
2967         extendedBounds.size.width -= horiontalRubberbandAmountInContentCoordinates;
2968     } else if (horiontalRubberbandAmountInContentCoordinates > 0)
2969         extendedBounds.size.width += horiontalRubberbandAmountInContentCoordinates;
2970
2971     if (verticalRubberbandAmountInContentCoordinates < 0) {
2972         extendedBounds.origin.y += verticalRubberbandAmountInContentCoordinates;
2973         extendedBounds.size.height -= verticalRubberbandAmountInContentCoordinates;
2974     } else if (verticalRubberbandAmountInContentCoordinates > 0)
2975         extendedBounds.size.height += verticalRubberbandAmountInContentCoordinates;
2976
2977     return extendedBounds;
2978 }
2979
2980 - (void)_updateVisibleContentRects
2981 {
2982     BOOL inStableState = _visibleContentRectUpdateScheduledFromScrollViewInStableState;
2983
2984     if (![self usesStandardContentView]) {
2985         [_passwordView setFrame:self.bounds];
2986         [_customContentView web_computedContentInsetDidChange];
2987         RELEASE_LOG_IF_ALLOWED("%p -[WKWebView _updateVisibleContentRects:] - usesStandardContentView is NO, bailing", self);
2988         return;
2989     }
2990
2991     if (_delayUpdateVisibleContentRects) {
2992         _hadDelayedUpdateVisibleContentRects = YES;
2993         RELEASE_LOG_IF_ALLOWED("%p -[WKWebView _updateVisibleContentRects:] - _delayUpdateVisibleContentRects is YES, bailing", self);
2994         return;
2995     }
2996
2997     if (_dynamicViewportUpdateMode != WebKit::DynamicViewportUpdateMode::NotResizing
2998         || (_needsResetViewStateAfterCommitLoadForMainFrame && ![_contentView sizeChangedSinceLastVisibleContentRectUpdate])
2999         || [_scrollView isZoomBouncing]
3000         || _currentlyAdjustingScrollViewInsetsForKeyboard) {
3001         RELEASE_LOG_IF_ALLOWED("%p -[WKWebView _updateVisibleContentRects:] - scroll view state is non-stable, bailing (_dynamicViewportUpdateMode %d, _needsResetViewStateAfterCommitLoadForMainFrame %d, sizeChangedSinceLastVisibleContentRectUpdate %d, [_scrollView isZoomBouncing] %d, _currentlyAdjustingScrollViewInsetsForKeyboard %d)",
3002             self, _dynamicViewportUpdateMode, _needsResetViewStateAfterCommitLoadForMainFrame, [_contentView sizeChangedSinceLastVisibleContentRectUpdate], [_scrollView isZoomBouncing], _currentlyAdjustingScrollViewInsetsForKeyboard);
3003         return;
3004     }
3005
3006     CGRect visibleRectInContentCoordinates = [self _visibleContentRect];
3007
3008     UIEdgeInsets computedContentInsetUnadjustedForKeyboard = [self _computedObscuredInset];
3009     if (!_haveSetObscuredInsets)
3010         computedContentInsetUnadjustedForKeyboard.bottom -= _totalScrollViewBottomInsetAdjustmentForKeyboard;
3011
3012     CGFloat scaleFactor = contentZoomScale(self);
3013
3014     CGRect unobscuredRect = UIEdgeInsetsInsetRect(self.bounds, computedContentInsetUnadjustedForKeyboard);
3015     CGRect unobscuredRectInContentCoordinates = _frozenUnobscuredContentRect ? _frozenUnobscuredContentRect.value() : [self convertRect:unobscuredRect toView:_contentView.get()];
3016     unobscuredRectInContentCoordinates = CGRectIntersection(unobscuredRectInContentCoordinates, [self _contentBoundsExtendedForRubberbandingWithScale:scaleFactor]);
3017
3018     // The following logic computes the extent to which the bottom, top, left and right content insets are visible.
3019     auto scrollViewInsets = [_scrollView contentInset];
3020     auto scrollViewBounds = [_scrollView bounds];
3021     auto scrollViewContentSize = [_scrollView contentSize];
3022     auto scrollViewOriginIncludingInset = UIEdgeInsetsInsetRect(scrollViewBounds, computedContentInsetUnadjustedForKeyboard).origin;
3023     auto maximumVerticalScrollExtentWithoutRevealingBottomContentInset = scrollViewContentSize.height - CGRectGetHeight(scrollViewBounds);
3024     auto maximumHorizontalScrollExtentWithoutRevealingRightContentInset = scrollViewContentSize.width - CGRectGetWidth(scrollViewBounds);
3025     auto contentInsets = UIEdgeInsetsZero;
3026     if (scrollViewInsets.left > 0 && scrollViewOriginIncludingInset.x < 0)
3027         contentInsets.left = std::min(-scrollViewOriginIncludingInset.x, scrollViewInsets.left) / scaleFactor;
3028
3029     if (scrollViewInsets.top > 0 && scrollViewOriginIncludingInset.y < 0)
3030         contentInsets.top = std::min(-scrollViewOriginIncludingInset.y, scrollViewInsets.top) / scaleFactor;
3031
3032     if (scrollViewInsets.right > 0 && scrollViewOriginIncludingInset.x > maximumHorizontalScrollExtentWithoutRevealingRightContentInset)
3033         contentInsets.right = std::min(scrollViewOriginIncludingInset.x - maximumHorizontalScrollExtentWithoutRevealingRightContentInset, scrollViewInsets.right) / scaleFactor;
3034
3035     if (scrollViewInsets.bottom > 0 && scrollViewOriginIncludingInset.y > maximumVerticalScrollExtentWithoutRevealingBottomContentInset)
3036         contentInsets.bottom = std::min(scrollViewOriginIncludingInset.y - maximumVerticalScrollExtentWithoutRevealingBottomContentInset, scrollViewInsets.bottom) / scaleFactor;
3037
3038 #if ENABLE(CSS_SCROLL_SNAP) && ENABLE(ASYNC_SCROLLING)
3039     if (inStableState) {
3040         WebKit::RemoteScrollingCoordinatorProxy* coordinator = _page->scrollingCoordinatorProxy();
3041         if (coordinator && coordinator->hasActiveSnapPoint()) {
3042             CGPoint currentPoint = [_scrollView contentOffset];
3043             CGPoint activePoint = coordinator->nearestActiveContentInsetAdjustedSnapPoint(unobscuredRect.origin.y, currentPoint);
3044
3045             if (!CGPointEqualToPoint(activePoint, currentPoint)) {
3046                 RetainPtr<WKScrollView> strongScrollView = _scrollView;
3047                 dispatch_async(dispatch_get_main_queue(), [strongScrollView, activePoint] {
3048                     [strongScrollView setContentOffset:activePoint animated:NO];
3049                 });
3050             }
3051         }
3052     }
3053 #endif
3054
3055     [_contentView didUpdateVisibleRect:visibleRectInContentCoordinates
3056         unobscuredRect:unobscuredRectInContentCoordinates
3057         contentInsets:contentInsets
3058         unobscuredRectInScrollViewCoordinates:unobscuredRect
3059         obscuredInsets:_obscuredInsets
3060         unobscuredSafeAreaInsets:[self _computedUnobscuredSafeAreaInset]
3061         inputViewBounds:_inputViewBounds
3062         scale:scaleFactor minimumScale:[_scrollView minimumZoomScale]
3063         inStableState:inStableState
3064         isChangingObscuredInsetsInteractively:_isChangingObscuredInsetsInteractively
3065         enclosedInScrollableAncestorView:scrollViewCanScroll([self _scroller])];
3066
3067     while (!_visibleContentRectUpdateCallbacks.isEmpty()) {
3068         auto callback = _visibleContentRectUpdateCallbacks.takeLast();
3069         callback();
3070     }
3071     
3072     auto timeNow = MonotonicTime::now();
3073     if ((timeNow - _timeOfRequestForVisibleContentRectUpdate) > delayBeforeNoVisibleContentsRectsLogging)
3074         RELEASE_LOG_IF_ALLOWED("%p -[WKWebView _updateVisibleContentRects:] finally ran %.2fs after being scheduled", self, (timeNow - _timeOfRequestForVisibleContentRectUpdate).value());
3075
3076     _timeOfLastVisibleContentRectUpdate = timeNow;
3077 }
3078
3079 - (void)_didStartProvisionalLoadForMainFrame
3080 {
3081     if (_gestureController)
3082         _gestureController->didStartProvisionalLoadForMainFrame();
3083 }
3084
3085 static WebCore::FloatSize activeMaximumUnobscuredSize(WKWebView *webView, const CGRect& bounds)
3086 {
3087     return WebCore::FloatSize(webView->_overridesMaximumUnobscuredSize ? webView->_maximumUnobscuredSizeOverride : bounds.size);
3088 }
3089
3090 static int32_t activeOrientation(WKWebView *webView)
3091 {
3092     return webView->_overridesInterfaceOrientation ? deviceOrientationForUIInterfaceOrientation(webView->_interfaceOrientationOverride) : webView->_page->deviceOrientation();
3093 }
3094
3095 - (void)_cancelAnimatedResize
3096 {
3097     LOG_WITH_STREAM(VisibleRects, stream << "-[WKWebView " << _page->pageID() << " _cancelAnimatedResize:] " << " _dynamicViewportUpdateMode " << (int)_dynamicViewportUpdateMode);
3098     if (_dynamicViewportUpdateMode == WebKit::DynamicViewportUpdateMode::NotResizing)
3099         return;
3100
3101     if (!_customContentView) {
3102         if (_resizeAnimationView) {
3103             NSUInteger indexOfResizeAnimationView = [[_scrollView subviews] indexOfObject:_resizeAnimationView.get()];
3104             [_scrollView insertSubview:_contentView.get() atIndex:indexOfResizeAnimationView];
3105             [_scrollView insertSubview:[_contentView unscaledView] atIndex:indexOfResizeAnimationView + 1];
3106             [_resizeAnimationView removeFromSuperview];
3107             _resizeAnimationView = nil;
3108         }
3109
3110         [_contentView setHidden:NO];
3111         _resizeAnimationTransformAdjustments = CATransform3DIdentity;
3112     }
3113
3114     _dynamicViewportUpdateMode = WebKit::DynamicViewportUpdateMode::NotResizing;
3115     [self _scheduleVisibleContentRectUpdate];
3116 }
3117
3118 - (void)_didCompleteAnimatedResize
3119 {
3120     if (_dynamicViewportUpdateMode == WebKit::DynamicViewportUpdateMode::NotResizing)
3121         return;
3122
3123     [_contentView setHidden:NO];
3124
3125     if (!_resizeAnimationView) {
3126         // Paranoia. If _resizeAnimationView is null we'll end up setting a zero scale on the content view.
3127         RELEASE_LOG_IF_ALLOWED("%p -[WKWebView _didCompleteAnimatedResize:] - _resizeAnimationView is nil", self);
3128         [self _cancelAnimatedResize];
3129         return;
3130     }
3131
3132     NSUInteger indexOfResizeAnimationView = [[_scrollView subviews] indexOfObject:_resizeAnimationView.get()];
3133     [_scrollView insertSubview:_contentView.get() atIndex:indexOfResizeAnimationView];
3134     [_scrollView insertSubview:[_contentView unscaledView] atIndex:indexOfResizeAnimationView + 1];
3135
3136     CALayer *contentLayer = [_contentView layer];
3137     CGFloat adjustmentScale = _resizeAnimationTransformAdjustments.m11;
3138     contentLayer.sublayerTransform = CATransform3DIdentity;
3139
3140     CGFloat animatingScaleTarget = [[_resizeAnimationView layer] transform].m11;
3141     CATransform3D contentLayerTransform = contentLayer.transform;
3142     CGFloat currentScale = [[_resizeAnimationView layer] transform].m11 * contentLayerTransform.m11;
3143
3144     // We cannot use [UIScrollView setZoomScale:] directly because the UIScrollView delegate would get a callback with
3145     // an invalid contentOffset. The real content offset is only set below.
3146     // Since there is no public API for setting both the zoomScale and the contentOffset, we set the zoomScale manually
3147     // on the zoom layer and then only change the contentOffset.
3148     CGFloat adjustedScale = adjustmentScale * currentScale;
3149     contentLayerTransform.m11 = adjustedScale;
3150     contentLayerTransform.m22 = adjustedScale;
3151     contentLayer.transform = contentLayerTransform;
3152
3153     CGPoint currentScrollOffset = [_scrollView contentOffset];
3154     double horizontalScrollAdjustement = _resizeAnimationTransformAdjustments.m41 * animatingScaleTarget;
3155     double verticalScrollAdjustment = _resizeAnimationTransformAdjustments.m42 * animatingScaleTarget;
3156
3157     [_scrollView setContentSize:roundScrollViewContentSize(*_page, [_contentView frame].size)];
3158     [_scrollView setContentOffset:CGPointMake(currentScrollOffset.x - horizontalScrollAdjustement, currentScrollOffset.y - verticalScrollAdjustment)];
3159
3160     [_resizeAnimationView removeFromSuperview];
3161     _resizeAnimationView = nil;
3162     _resizeAnimationTransformAdjustments = CATransform3DIdentity;
3163
3164     _dynamicViewportUpdateMode = WebKit::DynamicViewportUpdateMode::NotResizing;
3165     [self _scheduleVisibleContentRectUpdate];
3166
3167     CGRect newBounds = self.bounds;
3168     auto newViewLayoutSize = [self activeViewLayoutSize:newBounds];
3169     auto newMaximumUnobscuredSize = activeMaximumUnobscuredSize(self, newBounds);
3170     int32_t newOrientation = activeOrientation(self);
3171
3172     if (!_lastSentViewLayoutSize || newViewLayoutSize != _lastSentViewLayoutSize.value())
3173         [self _dispatchSetViewLayoutSize:newViewLayoutSize];
3174
3175     if (!_lastSentMaximumUnobscuredSize || newMaximumUnobscuredSize != _lastSentMaximumUnobscuredSize.value())
3176         [self _dispatchSetMaximumUnobscuredSize:WebCore::FloatSize(newMaximumUnobscuredSize)];
3177
3178     if (!_lastSentDeviceOrientation || newOrientation != _lastSentDeviceOrientation.value())
3179         [self _dispatchSetDeviceOrientation:newOrientation];
3180
3181     while (!_callbacksDeferredDuringResize.isEmpty())
3182         _callbacksDeferredDuringResize.takeLast()();
3183 }
3184
3185 - (void)_didFinishLoadForMainFrame
3186 {
3187     if (_gestureController)
3188         _gestureController->didFinishLoadForMainFrame();
3189 }
3190
3191 - (void)_didFailLoadForMainFrame
3192 {
3193     if (_gestureController)
3194         _gestureController->didFailLoadForMainFrame();
3195 }
3196
3197 - (void)_didSameDocumentNavigationForMainFrame:(WebKit::SameDocumentNavigationType)navigationType
3198 {
3199     [_customContentView web_didSameDocumentNavigation:toAPI(navigationType)];
3200
3201     if (_gestureController)
3202         _gestureController->didSameDocumentNavigationForMainFrame(navigationType);
3203 }
3204
3205 - (void)_keyboardChangedWithInfo:(NSDictionary *)keyboardInfo adjustScrollView:(BOOL)adjustScrollView
3206 {
3207     NSValue *endFrameValue = [keyboardInfo objectForKey:UIKeyboardFrameEndUserInfoKey];
3208     if (!endFrameValue)
3209         return;
3210
3211     // The keyboard rect is always in screen coordinates. In the view services case the window does not
3212     // have the interface orientation rotation transformation; its host does. So, it makes no sense to
3213     // clip the keyboard rect against its screen.
3214     if ([[self window] _isHostedInAnotherProcess])
3215         _inputViewBounds = [self.window convertRect:[endFrameValue CGRectValue] fromWindow:nil];
3216     else
3217         _inputViewBounds = [self.window convertRect:CGRectIntersection([endFrameValue CGRectValue], self.window.screen.bounds) fromWindow:nil];
3218
3219     if ([[UIPeripheralHost sharedInstance] isUndocked])
3220         _inputViewBounds = CGRectZero;
3221
3222     if (adjustScrollView) {
3223         CGFloat bottomInsetBeforeAdjustment = [_scrollView contentInset].bottom;
3224         SetForScope<BOOL> insetAdjustmentGuard(_currentlyAdjustingScrollViewInsetsForKeyboard, YES);
3225         [_scrollView _adjustForAutomaticKeyboardInfo:keyboardInfo animated:YES lastAdjustment:&_lastAdjustmentForScroller];
3226         CGFloat bottomInsetAfterAdjustment = [_scrollView contentInset].bottom;
3227         if (bottomInsetBeforeAdjustment != bottomInsetAfterAdjustment)
3228             _totalScrollViewBottomInsetAdjustmentForKeyboard += bottomInsetAfterAdjustment - bottomInsetBeforeAdjustment;
3229     }
3230
3231     [self _scheduleVisibleContentRectUpdate];
3232 }
3233
3234 - (BOOL)_shouldUpdateKeyboardWithInfo:(NSDictionary *)keyboardInfo
3235 {
3236     if ([_contentView isFocusingElement])
3237         return YES;
3238
3239     NSNumber *isLocalKeyboard = [keyboardInfo valueForKey:UIKeyboardIsLocalUserInfoKey];
3240     return isLocalKeyboard && !isLocalKeyboard.boolValue;
3241 }
3242
3243 - (void)_keyboardWillChangeFrame:(NSNotification *)notification
3244 {
3245     if ([self _shouldUpdateKeyboardWithInfo:notification.userInfo])
3246         [self _keyboardChangedWithInfo:notification.userInfo adjustScrollView:YES];
3247 }
3248
3249 - (void)_keyboardDidChangeFrame:(NSNotification *)notification
3250 {
3251     [self _keyboardChangedWithInfo:notification.userInfo adjustScrollView:NO];
3252 }
3253
3254 - (void)_keyboardWillShow:(NSNotification *)notification
3255 {
3256     if ([self _shouldUpdateKeyboardWithInfo:notification.userInfo])
3257         [self _keyboardChangedWithInfo:notification.userInfo adjustScrollView:YES];
3258
3259     _page->setIsKeyboardAnimatingIn(true);
3260 }
3261
3262 - (void)_keyboardDidShow:(NSNotification *)notification
3263 {
3264     _page->setIsKeyboardAnimatingIn(false);
3265 }
3266
3267 - (void)_keyboardWillHide:(NSNotification *)notification
3268 {
3269     // Ignore keyboard will hide notifications sent during rotation. They're just there for
3270     // backwards compatibility reasons and processing the will hide notification would
3271     // temporarily screw up the unobscured view area.
3272     if ([[UIPeripheralHost sharedInstance] rotationState])
3273         return;
3274
3275     [self _keyboardChangedWithInfo:notification.userInfo adjustScrollView:YES];
3276 }
3277
3278 static void hardwareKeyboardAvailabilityChangedCallback(CFNotificationCenterRef, void* observer, CFStringRef, const void*, CFDictionaryRef)
3279 {
3280     ASSERT(observer);
3281     WKWebView *webView = (__bridge WKWebView *)observer;
3282     webView._page->hardwareKeyboardAvailabilityChanged();
3283 }
3284
3285 - (void)_windowDidRotate:(NSNotification *)notification
3286 {
3287     if (!_overridesInterfaceOrientation)
3288         [self _dispatchSetDeviceOrientation:deviceOrientation()];
3289 }
3290
3291 - (void)_contentSizeCategoryDidChange:(NSNotification *)notification
3292 {
3293     _page->contentSizeCategoryDidChange([self _contentSizeCategory]);
3294 }
3295
3296 - (NSString *)_contentSizeCategory
3297 {
3298     return [[UIApplication sharedApplication] preferredContentSizeCategory];
3299 }
3300
3301 - (void)_accessibilitySettingsDidChange:(NSNotification *)notification
3302 {
3303     _page->accessibilitySettingsDidChange();
3304 }
3305
3306 - (void)setAllowsBackForwardNavigationGestures:(BOOL)allowsBackForwardNavigationGestures
3307 {
3308     if (_allowsBackForwardNavigationGestures == allowsBackForwardNavigationGestures)
3309         return;
3310
3311     _allowsBackForwardNavigationGestures = allowsBackForwardNavigationGestures;
3312
3313     if (allowsBackForwardNavigationGestures && !_gestureController) {
3314         _gestureController = std::make_unique<WebKit::ViewGestureController>(*_page);
3315         _gestureController->installSwipeHandler(self, [self scrollView]);
3316         if (WKWebView *alternateWebView = [_configuration _alternateWebViewForNavigationGestures])
3317             _gestureController->setAlternateBackForwardListSourcePage(alternateWebView->_page.get());
3318     }
3319
3320     if (_gestureController)
3321         _gestureController->setSwipeGestureEnabled(allowsBackForwardNavigationGestures);
3322
3323     _page->setShouldRecordNavigationSnapshots(allowsBackForwardNavigationGestures);
3324 }
3325
3326 - (BOOL)allowsBackForwardNavigationGestures
3327 {
3328     return _allowsBackForwardNavigationGestures;
3329 }
3330
3331 - (BOOL)_isNavigationSwipeGestureRecognizer:(UIGestureRecognizer *)recognizer
3332 {
3333     if (!_gestureController)
3334         return NO;
3335     return _gestureController->isNavigationSwipeGestureRecognizer(recognizer);
3336 }
3337
3338 - (void)_navigationGestureDidBegin
3339 {
3340     // During a back/forward swipe, there's a view interposed between this view and the content view that has
3341     // an offset and animation on it, which results in computing incorrect rectangles. Work around by using
3342     // frozen rects during swipes.
3343     CGRect fullViewRect = self.bounds;
3344     CGRect unobscuredRect = UIEdgeInsetsInsetRect(fullViewRect, [self _computedObscuredInset]);
3345
3346     _frozenVisibleContentRect = [self convertRect:fullViewRect toView:_contentView.get()];
3347     _frozenUnobscuredContentRect = [self convertRect:unobscuredRect toView:_contentView.get()];
3348
3349     LOG_WITH_STREAM(VisibleRects, stream << "_navigationGestureDidBegin: freezing visibleContentRect " << WebCore::FloatRect(_frozenVisibleContentRect.value()) << " UnobscuredContentRect " << WebCore::FloatRect(_frozenUnobscuredContentRect.value()));
3350 }
3351
3352 - (void)_navigationGestureDidEnd
3353 {
3354     _frozenVisibleContentRect = WTF::nullopt;
3355     _frozenUnobscuredContentRect = WTF::nullopt;
3356 }
3357
3358 - (void)_showPasswordViewWithDocumentName:(NSString *)documentName passwordHandler:(void (^)(NSString *))passwordHandler
3359 {
3360     ASSERT(!_passwordView);
3361     _passwordView = adoptNS([[WKPasswordView alloc] initWithFrame:self.bounds documentName:documentName]);
3362     [_passwordView setUserDidEnterPassword:passwordHandler];
3363     [_passwordView showInScrollView:_scrollView.get()];
3364     self._currentContentView.hidden = YES;
3365 }
3366
3367 - (void)_hidePasswordView
3368 {
3369     if (!_passwordView)
3370         return;
3371
3372     self._currentContentView.hidden = NO;
3373     [_passwordView hide];
3374     _passwordView = nil;
3375 }
3376
3377 - (WKPasswordView *)_passwordView
3378 {
3379     return _passwordView.get();
3380 }
3381
3382 - (void)_updateScrollViewInsetAdjustmentBehavior
3383 {
3384 #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000
3385     if (![_scrollView _contentInsetAdjustmentBehaviorWasExternallyOverridden])
3386         [_scrollView _setContentInsetAdjustmentBehaviorInternal:self._safeAreaShouldAffectObscuredInsets ? UIScrollViewContentInsetAdjustmentAlways : UIScrollViewContentInsetAdjustmentNever];
3387 #endif
3388 }
3389
3390 - (void)_setAvoidsUnsafeArea:(BOOL)avoidsUnsafeArea
3391 {
3392     if (_avoidsUnsafeArea == avoidsUnsafeArea)
3393         return;
3394
3395     _avoidsUnsafeArea = avoidsUnsafeArea;
3396
3397     [self _updateScrollViewInsetAdjustmentBehavior];
3398     [self _scheduleVisibleContentRectUpdate];
3399
3400     id <WKUIDelegatePrivate> uiDelegate = (id <WKUIDelegatePrivate>)[self UIDelegate];
3401     if ([uiDelegate respondsToSelector:@selector(_webView:didChangeSafeAreaShouldAffectObscuredInsets:)])
3402         [uiDelegate _webView:self didChangeSafeAreaShouldAffectObscuredInsets:avoidsUnsafeArea];
3403 }
3404
3405 - (BOOL)_haveSetObscuredInsets
3406 {
3407     return _haveSetObscuredInsets;
3408 }
3409
3410 #endif // PLATFORM(IOS_FAMILY)
3411
3412 #if ENABLE(ACCESSIBILITY_EVENTS)
3413
3414 static void accessibilityEventsEnabledChangedCallback(CFNotificationCenterRef, void* observer, CFStringRef, const void*, CFDictionaryRef)
3415 {
3416     ASSERT(observer);
3417     WKWebView *webview = (__bridge WKWebView *)observer;
3418     [webview _updateAccessibilityEventsEnabled];
3419 }
3420
3421 - (void)_updateAccessibilityEventsEnabled
3422 {
3423     if (!isNullFunctionPointer(_AXSWebAccessibilityEventsEnabled))
3424         _page->updateAccessibilityEventsEnabled(_AXSWebAccessibilityEventsEnabled());
3425 }
3426
3427 #endif
3428
3429 #pragma mark OS X-specific methods
3430
3431 #if PLATFORM(MAC)
3432
3433 - (BOOL)acceptsFirstResponder
3434 {
3435     return _impl->acceptsFirstResponder();
3436 }
3437
3438 - (BOOL)becomeFirstResponder
3439 {
3440     return _impl->becomeFirstResponder();
3441 }
3442
3443 - (BOOL)resignFirstResponder
3444 {
3445     return _impl->resignFirstResponder();
3446 }
3447
3448 - (void)viewWillStartLiveResize
3449 {
3450     _impl->viewWillStartLiveResize();
3451 }
3452
3453 - (void)viewDidEndLiveResize
3454 {
3455     _impl->viewDidEndLiveResize();
3456 }
3457
3458 - (BOOL)isFlipped
3459 {
3460     return YES;
3461 }
3462
3463 - (NSSize)intrinsicContentSize
3464 {
3465     return NSSizeFromCGSize(_impl->intrinsicContentSize());
3466 }
3467
3468 - (void)prepareContentInRect:(NSRect)rect
3469 {
3470     _impl->prepareContentInRect(NSRectToCGRect(rect));
3471 }
3472
3473 - (void)setFrameSize:(NSSize)size
3474 {
3475     [super setFrameSize:size];
3476     [_safeBrowsingWarning setFrame:self.bounds];
3477     _impl->setFrameSize(NSSizeToCGSize(size));
3478 }
3479
3480 IGNORE_WARNINGS_BEGIN("deprecated-implementations")
3481 - (void)renewGState
3482 IGNORE_WARNINGS_END
3483 {
3484     _impl->renewGState();
3485     [super renewGState];
3486 }
3487
3488 #define WEBCORE_COMMAND(command) - (void)command:(id)sender { _impl->executeEditCommandForSelector(_cmd); }
3489
3490 WEBCORE_COMMAND(alignCenter)
3491 WEBCORE_COMMAND(alignJustified)
3492 WEBCORE_COMMAND(alignLeft)
3493 WEBCORE_COMMAND(alignRight)
3494 WEBCORE_COMMAND(copy)
3495 WEBCORE_COMMAND(cut)
3496 WEBCORE_COMMAND(delete)
3497 WEBCORE_COMMAND(deleteBackward)
3498 WEBCORE_COMMAND(deleteBackwardByDecomposingPreviousCharacter)
3499 WEBCORE_COMMAND(deleteForward)
3500 WEBCORE_COMMAND(deleteToBeginningOfLine)
3501 WEBCORE_COMMAND(deleteToBeginningOfParagraph)
3502 WEBCORE_COMMAND(deleteToEndOfLine)
3503 WEBCORE_COMMAND(deleteToEndOfParagraph)
3504 WEBCORE_COMMAND(deleteToMark)
3505 WEBCORE_COMMAND(deleteWordBackward)
3506 WEBCORE_COMMAND(deleteWordForward)
3507 WEBCORE_COMMAND(ignoreSpelling)
3508 WEBCORE_COMMAND(indent)
3509 WEBCORE_COMMAND(insertBacktab)
3510 WEBCORE_COMMAND(insertLineBreak)
3511 WEBCORE_COMMAND(insertNewline)
3512 WEBCORE_COMMAND(insertNewlineIgnoringFieldEditor)
3513 WEBCORE_COMMAND(insertParagraphSeparator)
3514 WEBCORE_COMMAND(insertTab)
3515 WEBCORE_COMMAND(insertTabIgnoringFieldEditor)
3516 WEBCORE_COMMAND(makeTextWritingDirectionLeftToRight)
3517 WEBCORE_COMMAND(makeTextWritingDirectionNatural)
3518 WEBCORE_COMMAND(makeTextWritingDirectionRightToLeft)
3519 WEBCORE_COMMAND(moveBackward)
3520 WEBCORE_COMMAND(moveBackwardAndModifySelection)
3521 WEBCORE_COMMAND(moveDown)
3522 WEBCORE_COMMAND(moveDownAndModifySelection)
3523 WEBCORE_COMMAND(moveForward)
3524 WEBCORE_COMMAND(moveForwardAndModifySelection)
3525 WEBCORE_COMMAND(moveLeft)
3526 WEBCORE_COMMAND(moveLeftAndModifySelection)
3527 WEBCORE_COMMAND(moveParagraphBackwardAndModifySelection)
3528 WEBCORE_COMMAND(moveParagraphForwardAndModifySelection)
3529 WEBCORE_COMMAND(moveRight)
3530 WEBCORE_COMMAND(moveRightAndModifySelection)
3531 WEBCORE_COMMAND(moveToBeginningOfDocument)
3532 WEBCORE_COMMAND(moveToBeginningOfDocumentAndModifySelection)
3533 WEBCORE_COMMAND(moveToBeginningOfLine)
3534 WEBCORE_COMMAND(moveToBeginningOfLineAndModifySelection)
3535 WEBCORE_COMMAND(moveToBeginningOfParagraph)
3536 WEBCORE_COMMAND(moveToBeginningOfParagraphAndModifySelection)
3537 WEBCORE_COMMAND(moveToBeginningOfSentence)
3538 WEBCORE_COMMAND(moveToBeginningOfSentenceAndModifySelection)
3539 WEBCORE_COMMAND(moveToEndOfDocument)
3540 WEBCORE_COMMAND(moveToEndOfDocumentAndModifySelection)
3541 WEBCORE_COMMAND(moveToEndOfLine)
3542 WEBCORE_COMMAND(moveToEndOfLineAndModifySelection)
3543 WEBCORE_COMMAND(moveToEndOfParagraph)
3544 WEBCORE_COMMAND(moveToEndOfParagraphAndModifySelection)
3545 WEBCORE_COMMAND(moveToEndOfSentence)
3546 WEBCORE_COMMAND(moveToEndOfSentenceAndModifySelection)
3547 WEBCORE_COMMAND(moveToLeftEndOfLine)
3548 WEBCORE_COMMAND(moveToLeftEndOfLineAndModifySelection)
3549 WEBCORE_COMMAND(moveToRightEndOfLine)
3550 WEBCORE_COMMAND(moveToRightEndOfLineAndModifySelection)
3551 WEBCORE_COMMAND(moveUp)
3552 WEBCORE_COMMAND(moveUpAndModifySelection)
3553 WEBCORE_COMMAND(moveWordBackward)
3554 WEBCORE_COMMAND(moveWordBackwardAndModifySelection)
3555 WEBCORE_COMMAND(moveWordForward)
3556 WEBCORE_COMMAND(moveWordForwardAndModifySelection)
3557 WEBCORE_COMMAND(moveWordLeft)
3558 WEBCORE_COMMAND(moveWordLeftAndModifySelection)
3559 WEBCORE_COMMAND(moveWordRight)
3560 WEBCORE_COMMAND(moveWordRightAndModifySelection)
3561 WEBCORE_COMMAND(outdent)
3562 WEBCORE_COMMAND(pageDown)
3563 WEBCORE_COMMAND(pageDownAndModifySelection)
3564 WEBCORE_COMMAND(pageUp)
3565 WEBCORE_COMMAND(pageUpAndModifySelection)
3566 WEBCORE_COMMAND(paste)
3567 WEBCORE_COMMAND(pasteAsPlainText)
3568 WEBCORE_COMMAND(scrollPageDown)
3569 WEBCORE_COMMAND(scrollPageUp)
3570 WEBCORE_COMMAND(scrollLineDown)
3571 WEBCORE_COMMAND(scrollLineUp)
3572 WEBCORE_COMMAND(scrollToBeginningOfDocument)
3573 WEBCORE_COMMAND(scrollToEndOfDocument)
3574 WEBCORE_COMMAND(selectAll)
3575 WEBCORE_COMMAND(selectLine)
3576 WEBCORE_COMMAND(selectParagraph)
3577 WEBCORE_COMMAND(selectSentence)
3578 WEBCORE_COMMAND(selectToMark)
3579 WEBCORE_COMMAND(selectWord)
3580 WEBCORE_COMMAND(setMark)
3581 WEBCORE_COMMAND(subscript)
3582 WEBCORE_COMMAND(superscript)
3583 WEBCORE_COMMAND(swapWithMark)
3584 WEBCORE_COMMAND(takeFindStringFromSelection)
3585 WEBCORE_COMMAND(transpose)
3586 WEBCORE_COMMAND(underline)
3587 WEBCORE_COMMAND(unscript)
3588 WEBCORE_COMMAND(yank)
3589 WEBCORE_COMMAND(yankAndSelect)
3590
3591 #undef WEBCORE_COMMAND
3592
3593 - (BOOL)writeSelectionToPasteboard:(NSPasteboard *)pasteboard types:(NSArray *)types
3594 {
3595     return _impl->writeSelectionToPasteboard(pasteboard, types);
3596 }
3597
3598 - (void)centerSelectionInVisibleArea:(id)sender
3599 {
3600     _impl->centerSelectionInVisibleArea();
3601 }
3602
3603 - (id)validRequestorForSendType:(NSString *)sendType returnType:(NSString *)returnType
3604 {
3605     return _impl->validRequestorForSendAndReturnTypes(sendType, returnType);
3606 }
3607
3608 - (BOOL)readSelectionFromPasteboard:(NSPasteboard *)pasteboard
3609 {
3610     return _impl->readSelectionFromPasteboard(pasteboard);
3611 }
3612
3613 - (void)changeFont:(id)sender
3614 {
3615     _impl->changeFontFromFontManager();
3616 }
3617
3618 - (void)changeColor:(id)sender
3619 {
3620     _impl->changeFontColorFromSender(sender);
3621 }
3622
3623 - (void)changeAttributes:(id)sender
3624 {
3625     _impl->changeFontAttributesFromSender(sender);
3626 }
3627
3628 - (IBAction)startSpeaking:(id)sender
3629 {
3630     _impl->startSpeaking();
3631 }
3632
3633 - (IBAction)stopSpeaking:(id)sender
3634 {
3635     _impl->stopSpeaking(sender);
3636 }
3637
3638 - (IBAction)showGuessPanel:(id)sender
3639 {
3640     _impl->showGuessPanel(sender);
3641 }
3642
3643 - (IBAction)checkSpelling:(id)sender
3644 {
3645     _impl->checkSpelling();
3646 }
3647
3648 - (void)changeSpelling:(id)sender
3649 {
3650     _impl->changeSpelling(sender);
3651 }
3652
3653 - (IBAction)toggleContinuousSpellChecking:(id)sender
3654 {
3655     _impl->toggleContinuousSpellChecking();
3656 }
3657
3658 - (BOOL)isGrammarCheckingEnabled
3659 {
3660     return _impl->isGrammarCheckingEnabled();
3661 }
3662
3663 - (void)setGrammarCheckingEnabled:(BOOL)flag
3664 {
3665     _impl->setGrammarCheckingEnabled(flag);
3666 }
3667
3668 - (IBAction)toggleGrammarChecking:(id)sender
3669 {
3670     _impl->toggleGrammarChecking();
3671 }
3672
3673 - (IBAction)toggleAutomaticSpellingCorrection:(id)sender
3674 {
3675     _impl->toggleAutomaticSpellingCorrection();
3676 }
3677
3678 - (void)orderFrontSubstitutionsPanel:(id)sender
3679 {
3680     _impl->orderFrontSubstitutionsPanel(sender);
3681 }
3682
3683 - (IBAction)toggleSmartInsertDelete:(id)sender
3684 {
3685     _impl->toggleSmartInsertDelete();
3686 }
3687
3688 - (BOOL)isAutomaticQuoteSubstitutionEnabled
3689 {
3690     return _impl->isAutomaticQuoteSubstitutionEnabled();
3691 }
3692
3693 - (void)setAutomaticQuoteSubstitutionEnabled:(BOOL)flag
3694 {
3695     _impl->setAutomaticQuoteSubstitutionEnabled(flag);
3696 }
3697
3698 - (void)toggleAutomaticQuoteSubstitution:(id)sender
3699 {
3700     _impl->toggleAutomaticQuoteSubstitution();
3701 }
3702
3703 - (BOOL)isAutomaticDashSubstitutionEnabled
3704 {
3705     return _impl->isAutomaticDashSubstitutionEnabled();
3706 }
3707
3708 - (void)setAutomaticDashSubstitutionEnabled:(BOOL)flag
3709 {
3710     _impl->setAutomaticDashSubstitutionEnabled(flag);
3711 }
3712
3713 - (void)toggleAutomaticDashSubstitution:(id)sender
3714 {
3715     _impl->toggleAutomaticDashSubstitution();
3716 }
3717
3718 - (BOOL)isAutomaticLinkDetectionEnabled
3719 {
3720     return _impl->isAutomaticLinkDetectionEnabled();
3721 }
3722
3723 - (void)setAutomaticLinkDetectionEnabled:(BOOL)flag
3724 {
3725     _impl->setAutomaticLinkDetectionEnabled(flag);
3726 }
3727
3728 - (void)toggleAutomaticLinkDetection:(id)sender
3729 {
3730     _impl->toggleAutomaticLinkDetection();
3731 }
3732
3733 - (BOOL)isAutomaticTextReplacementEnabled
3734 {
3735     return _impl->isAutomaticTextReplacementEnabled();
3736 }
3737
3738 - (void)setAutomaticTextReplacementEnabled:(BOOL)flag
3739 {
3740     _impl->setAutomaticTextReplacementEnabled(flag);
3741 }
3742
3743 - (void)toggleAutomaticTextReplacement:(id)sender
3744 {
3745     _impl->toggleAutomaticTextReplacement();
3746 }
3747
3748 - (void)uppercaseWord:(id)sender
3749 {
3750     _impl->uppercaseWord();
3751 }
3752
3753 - (void)lowercaseWord:(id)sender
3754 {
3755     _impl->lowercaseWord();
3756 }
3757
3758 - (void)capitalizeWord:(id)sender
3759 {
3760     _impl->capitalizeWord();
3761 }
3762
3763 - (BOOL)_wantsKeyDownForEvent:(NSEvent *)event
3764 {
3765     return _impl->wantsKeyDownForEvent(event);
3766 }
3767
3768 - (void)scrollWheel:(NSEvent *)event
3769 {
3770     _impl->scrollWheel(event);
3771 }
3772
3773 - (void)swipeWithEvent:(NSEvent *)event
3774 {
3775     _impl->swipeWithEvent(event);
3776 }
3777
3778 - (void)mouseMoved:(NSEvent *)event
3779 {
3780     _impl->mouseMoved(event);
3781 }
3782
3783 - (void)mouseDown:(NSEvent *)event
3784 {
3785     _impl->mouseDown(event);
3786 }
3787
3788 - (void)mouseUp:(NSEvent *)event
3789 {
3790     _impl->mouseUp(event);
3791 }
3792
3793 - (void)mouseDragged:(NSEvent *)event
3794 {
3795     _impl->mouseDragged(event);
3796 }
3797
3798 - (void)mouseEntered:(NSEvent *)event
3799 {
3800     _impl->mouseEntered(event);
3801 }
3802
3803 - (void)mouseExited:(NSEvent *)event
3804 {
3805     _impl->mouseExited(event);
3806 }
3807
3808 - (void)otherMouseDown:(NSEvent *)event
3809 {
3810     _impl->otherMouseDown(event);
3811 }
3812
3813 - (void)otherMouseDragged:(NSEvent *)event
3814 {
3815     _impl->otherMouseDragged(event);
3816 }
3817
3818 - (void)otherMouseUp:(NSEvent *)event
3819 {
3820     _impl->otherMouseUp(event);
3821 }
3822
3823 - (void)rightMouseDown:(NSEvent *)event
3824 {
3825     _impl->rightMouseDown(event);
3826 }
3827
3828 - (void)rightMouseDragged:(NSEvent *)event
3829 {
3830     _impl->rightMouseDragged(event);
3831 }
3832
3833 - (void)rightMouseUp:(NSEvent *)event
3834 {
3835     _impl->rightMouseUp(event);
3836 }
3837
3838 - (void)pressureChangeWithEvent:(NSEvent *)event
3839 {
3840     _impl->pressureChangeWithEvent(event);
3841 }
3842
3843 - (BOOL)acceptsFirstMouse:(NSEvent *)event
3844 {
3845     return _impl->acceptsFirstMouse(event);
3846 }
3847
3848 - (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent *)event
3849 {
3850     return _impl->shouldDelayWindowOrderingForEvent(event);
3851 }
3852
3853 - (void)doCommandBySelector:(SEL)selector
3854 {
3855     _impl->doCommandBySelector(selector);
3856 }
3857
3858 - (void)insertText:(id)string
3859 {
3860     _impl->insertText(string);
3861 }
3862
3863 - (void)insertText:(id)string replacementRange:(NSRange)replacementRange
3864 {
3865     _impl->insertText(string, replacementRange);
3866 }
3867
3868 - (NSTextInputContext *)inputContext
3869 {
3870     if (!_impl)
3871         return nil;
3872     return _impl->inputContext();
3873 }
3874
3875 - (BOOL)performKeyEquivalent:(NSEvent *)event
3876 {
3877     return _impl->performKeyEquivalent(event);
3878 }
3879
3880 - (void)keyUp:(NSEvent *)theEvent
3881 {
3882     _impl->keyUp(theEvent);
3883 }
3884
3885 - (void)keyDown:(NSEvent *)theEvent
3886 {
3887     _impl->keyDown(theEvent);
3888 }
3889
3890 - (void)flagsChanged:(NSEvent *)theEvent
3891 {
3892     _impl->flagsChanged(theEvent);
3893 }
3894
3895 - (void)setMarkedText:(id)string selectedRange:(NSRange)newSelectedRange replacementRange:(NSRange)replacementRange
3896 {
3897     _impl->setMarkedText(string, newSelectedRange, replacementRange);
3898 }
3899
3900 - (void)unmarkText
3901 {
3902     _impl->unmarkText();
3903 }
3904
3905 - (NSRange)selectedRange
3906 {
3907     return _impl->selectedRange();
3908 }
3909
3910 - (BOOL)hasMarkedText
3911 {
3912     return _impl->hasMarkedText();
3913 }
3914
3915 - (NSRange)markedRange
3916 {
3917     return _impl->markedRange();
3918 }
3919
3920 - (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)nsRange actualRange:(NSRangePointer)actualRange
3921 {
3922     return _impl->attributedSubstringForProposedRange(nsRange, actualRange);
3923 }
3924
3925 - (NSUInteger)characterIndexForPoint:(NSPoint)thePoint
3926 {
3927     return _impl->characterIndexForPoint(thePoint);
3928 }
3929
3930 - (void)typingAttributesWithCompletionHandler:(void(^)(NSDictionary<NSString *, id> *))completion
3931 {
3932     _impl->typingAttributesWithCompletionHandler(completion);
3933 }
3934
3935 - (NSRect)firstRectForCharacterRange:(NSRange)theRange actualRange:(NSRangePointer)actualRange
3936 {
3937     return _impl->firstRectForCharacterRange(theRange, actualRange);
3938 }
3939
3940 - (void)selectedRangeWithCompletionHandler:(void(^)(NSRange selectedRange))completionHandlerPtr
3941 {
3942     _impl->selectedRangeWithCompletionHandler(completionHandlerPtr);
3943 }
3944
3945 - (void)markedRangeWithCompletionHandler:(void(^)(NSRange markedRange))completionHandlerPtr
3946 {
3947     _impl->markedRangeWithCompletionHandler(completionHandlerPtr);
3948 }
3949
3950 - (void)hasMarkedTextWithCompletionHandler:(void(^)(BOOL hasMarkedText))completionHandlerPtr
3951 {
3952     _impl->hasMarkedTextWithCompletionHandler(completionHandlerPtr);
3953 }
3954
3955 - (void)attributedSubstringForProposedRange:(NSRange)nsRange completionHandler:(void(^)(NSAttributedString *attrString, NSRange actualRange))completionHandlerPtr
3956 {
3957     _impl->attributedSubstringForProposedRange(nsRange, completionHandlerPtr);
3958 }
3959
3960 - (void)firstRectForCharacterRange:(NSRange)theRange completionHandler:(void(^)(NSRect firstRect, NSRange actualRange))completionHandlerPtr
3961 {
3962     _impl->firstRectForCharacterRange(theRange, completionHandlerPtr);
3963 }
3964
3965 - (void)characterIndexForPoint:(NSPoint)thePoint completionHandler:(void(^)(NSUInteger))completionHandlerPtr
3966 {
3967     _impl->characterIndexForPoint(thePoint, completionHandlerPtr);
3968 }
3969
3970 - (NSArray *)validAttributesForMarkedText
3971 {
3972     return _impl->validAttributesForMarkedText();
3973 }
3974
3975 #if ENABLE(DRAG_SUPPORT)
3976 IGNORE_WARNINGS_BEGIN("deprecated-implementations")
3977 - (void)draggedImage:(NSImage *)image endedAt:(NSPoint)endPoint operation:(NSDragOperation)operation
3978 IGNORE_WARNINGS_END
3979 {
3980     _impl->draggedImage(image, NSPointToCGPoint(endPoint), operation);
3981 }
3982
3983 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)draggingInfo
3984 {
3985     return _impl->draggingEntered(draggingInfo);
3986 }
3987
3988 - (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)draggingInfo
3989 {
3990     return _impl->draggingUpdated(draggingInfo);
3991 }
3992
3993 - (void)draggingExited:(id <NSDraggingInfo>)draggingInfo
3994 {
3995     _impl->draggingExited(draggingInfo);
3996 }
3997
3998 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)draggingInfo
3999 {
4000     return _impl->prepareForDragOperation(draggingInfo);
4001 }
4002
4003 - (BOOL)performDragOperation:(id <NSDraggingInfo>)draggingInfo
4004 {
4005     return _impl->performDragOperation(draggingInfo);
4006 }
4007
4008 - (NSView *)_hitTest:(NSPoint *)point dragTypes:(NSSet *)types
4009 {
4010     return _impl->hitTestForDragTypes(NSPointToCGPoint(*point), types);
4011 }
4012 #endif // ENABLE(DRAG_SUPPORT)
4013
4014 - (BOOL)_windowResizeMouseLocationIsInVisibleScrollerThumb:(NSPoint)point
4015 {
4016     return _impl->windowResizeMouseLocationIsInVisibleScrollerThumb(NSPointToCGPoint(point));
4017 }
4018
4019 - (void)viewWillMoveToWindow:(NSWindow *)window
4020 {
4021     _impl->viewWillMoveToWindow(window);
4022 }
4023
4024 - (void)viewDidMoveToWindow
4025 {
4026     _impl->viewDidMoveToWindow();
4027 }
4028
4029 - (void)drawRect:(NSRect)rect
4030 {
4031     _impl->drawRect(NSRectToCGRect(rect));
4032 }
4033
4034 - (BOOL)isOpaque
4035 {
4036     return _impl->isOpaque();
4037 }
4038
4039 - (BOOL)mouseDownCanMoveWindow
4040 {
4041     return WebKit::WebViewImpl::mouseDownCanMoveWindow();
4042 }
4043
4044 - (void)viewDidHide
4045 {
4046     _impl->viewDidHide();
4047 }
4048
4049 - (void)viewDidUnhide
4050 {
4051     _impl->viewDidUnhide();
4052 }
4053
4054 - (void)viewDidChangeBackingProperties
4055 {
4056     _impl->viewDidChangeBackingProperties();
4057 }
4058
4059 - (void)_activeSpaceDidChange:(NSNotification *)notification
4060 {
4061     _impl->activeSpaceDidChange();
4062 }