[iOS] ASSERTION FAILURE: !isMissingPostLayoutData in WebKit::EditorState::postLayoutD...
[WebKit-https.git] / Source / WebKit / WebProcess / WebPage / ios / WebPageIOS.mm
1 /*
2  * Copyright (C) 2012-2019 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 "WebPage.h"
28
29 #if PLATFORM(IOS_FAMILY)
30
31 #import "AccessibilityIOS.h"
32 #import "DataReference.h"
33 #import "DocumentEditingContext.h"
34 #import "DrawingArea.h"
35 #import "EditingRange.h"
36 #import "EditorState.h"
37 #import "InteractionInformationAtPosition.h"
38 #import "Logging.h"
39 #import "NativeWebKeyboardEvent.h"
40 #import "PluginView.h"
41 #import "PrintInfo.h"
42 #import "RemoteLayerTreeDrawingArea.h"
43 #import "SandboxUtilities.h"
44 #import "SharedMemory.h"
45 #import "SyntheticEditingCommandType.h"
46 #import "TextCheckingControllerProxy.h"
47 #import "UIKitSPI.h"
48 #import "UserData.h"
49 #import "ViewGestureGeometryCollector.h"
50 #import "VisibleContentRectUpdateInfo.h"
51 #import "WKAccessibilityWebPageObjectIOS.h"
52 #import "WebAutocorrectionContext.h"
53 #import "WebAutocorrectionData.h"
54 #import "WebChromeClient.h"
55 #import "WebCoreArgumentCoders.h"
56 #import "WebFrame.h"
57 #import "WebImage.h"
58 #import "WebPageMessages.h"
59 #import "WebPageProxyMessages.h"
60 #import "WebPreviewLoaderClient.h"
61 #import "WebProcess.h"
62 #import <CoreText/CTFont.h>
63 #import <WebCore/Autofill.h>
64 #import <WebCore/AutofillElements.h>
65 #import <WebCore/Chrome.h>
66 #import <WebCore/ContentChangeObserver.h>
67 #import <WebCore/DOMTimerHoldingTank.h>
68 #import <WebCore/DataDetection.h>
69 #import <WebCore/DiagnosticLoggingClient.h>
70 #import <WebCore/DiagnosticLoggingKeys.h>
71 #import <WebCore/DocumentLoader.h>
72 #import <WebCore/DragController.h>
73 #import <WebCore/Editing.h>
74 #import <WebCore/Editor.h>
75 #import <WebCore/EditorClient.h>
76 #import <WebCore/Element.h>
77 #import <WebCore/ElementAncestorIterator.h>
78 #import <WebCore/EventHandler.h>
79 #import <WebCore/File.h>
80 #import <WebCore/FloatQuad.h>
81 #import <WebCore/FocusController.h>
82 #import <WebCore/Frame.h>
83 #import <WebCore/FrameLoaderClient.h>
84 #import <WebCore/FrameView.h>
85 #import <WebCore/GeometryUtilities.h>
86 #import <WebCore/HTMLAreaElement.h>
87 #import <WebCore/HTMLAttachmentElement.h>
88 #import <WebCore/HTMLBodyElement.h>
89 #import <WebCore/HTMLElement.h>
90 #import <WebCore/HTMLElementTypeHelpers.h>
91 #import <WebCore/HTMLFormElement.h>
92 #import <WebCore/HTMLIFrameElement.h>
93 #import <WebCore/HTMLImageElement.h>
94 #import <WebCore/HTMLInputElement.h>
95 #import <WebCore/HTMLLabelElement.h>
96 #import <WebCore/HTMLOptGroupElement.h>
97 #import <WebCore/HTMLOptionElement.h>
98 #import <WebCore/HTMLParserIdioms.h>
99 #import <WebCore/HTMLSelectElement.h>
100 #import <WebCore/HTMLSummaryElement.h>
101 #import <WebCore/HTMLTextAreaElement.h>
102 #import <WebCore/HTMLTextFormControlElement.h>
103 #import <WebCore/HistoryItem.h>
104 #import <WebCore/HitTestResult.h>
105 #import <WebCore/InputMode.h>
106 #import <WebCore/KeyboardEvent.h>
107 #import <WebCore/LibWebRTCProvider.h>
108 #import <WebCore/MediaSessionManagerIOS.h>
109 #import <WebCore/Node.h>
110 #import <WebCore/NodeList.h>
111 #import <WebCore/NotImplemented.h>
112 #import <WebCore/Page.h>
113 #import <WebCore/Pasteboard.h>
114 #import <WebCore/PlatformKeyboardEvent.h>
115 #import <WebCore/PlatformMouseEvent.h>
116 #import <WebCore/PointerCaptureController.h>
117 #import <WebCore/Quirks.h>
118 #import <WebCore/RenderBlock.h>
119 #import <WebCore/RenderImage.h>
120 #import <WebCore/RenderLayer.h>
121 #import <WebCore/RenderThemeIOS.h>
122 #import <WebCore/RenderView.h>
123 #import <WebCore/RuntimeApplicationChecks.h>
124 #import <WebCore/Settings.h>
125 #import <WebCore/ShadowRoot.h>
126 #import <WebCore/SharedBuffer.h>
127 #import <WebCore/StyleProperties.h>
128 #import <WebCore/TextIndicator.h>
129 #import <WebCore/TextIterator.h>
130 #import <WebCore/TextPlaceholderElement.h>
131 #import <WebCore/UserAgent.h>
132 #import <WebCore/VisibleUnits.h>
133 #import <WebCore/WebEvent.h>
134 #import <wtf/MathExtras.h>
135 #import <wtf/MemoryPressureHandler.h>
136 #import <wtf/SetForScope.h>
137 #import <wtf/SoftLinking.h>
138 #import <wtf/cocoa/Entitlements.h>
139 #import <wtf/text/TextStream.h>
140
141 #define RELEASE_LOG_IF_ALLOWED(channel, fmt, ...) RELEASE_LOG_IF(isAlwaysOnLoggingAllowed(), channel, "%p - WebPage::" fmt, this, ##__VA_ARGS__)
142 #define RELEASE_LOG_ERROR_IF_ALLOWED(channel, fmt, ...) RELEASE_LOG_ERROR_IF(isAlwaysOnLoggingAllowed(), channel, "%p - WebPage::" fmt, this, ##__VA_ARGS__)
143
144 namespace WebKit {
145
146 // FIXME: Unclear if callers in this file are correctly choosing which of these two functions to use.
147
148 static String plainTextForContext(const Range* range)
149 {
150     if (!range)
151         return emptyString();
152     return WebCore::plainTextReplacingNoBreakSpace(*range);
153 }
154
155 static String plainTextForDisplay(const Range* range)
156 {
157     if (!range)
158         return emptyString();
159     return WebCore::plainTextReplacingNoBreakSpace(*range, TextIteratorDefaultBehavior, true);
160 }
161
162 void WebPage::platformInitialize()
163 {
164     platformInitializeAccessibility();
165 }
166
167 void WebPage::platformDetach()
168 {
169     [m_mockAccessibilityElement setWebPage:nullptr];
170 }
171     
172 void WebPage::platformInitializeAccessibility()
173 {
174     m_mockAccessibilityElement = adoptNS([[WKAccessibilityWebPageObject alloc] init]);
175     [m_mockAccessibilityElement setWebPage:this];
176
177     accessibilityTransferRemoteToken(accessibilityRemoteTokenData());
178 }
179
180 void WebPage::platformReinitialize()
181 {
182     accessibilityTransferRemoteToken(accessibilityRemoteTokenData());
183 }
184
185 RetainPtr<NSData> WebPage::accessibilityRemoteTokenData() const
186 {
187     return newAccessibilityRemoteToken([NSUUID UUID]);
188 }
189
190 static void computeEditableRootHasContentAndPlainText(const VisibleSelection& selection, EditorState::PostLayoutData& data)
191 {
192     data.hasContent = false;
193     data.hasPlainText = false;
194     if (!selection.isContentEditable())
195         return;
196
197     if (data.selectedTextLength || data.characterAfterSelection || data.characterBeforeSelection || data.twoCharacterBeforeSelection) {
198         // If any of these variables have been previously set, the editable root must have plain text content, so we can bail from the remainder of the check.
199         data.hasContent = true;
200         data.hasPlainText = true;
201         return;
202     }
203
204     auto* root = selection.rootEditableElement();
205     if (!root)
206         return;
207
208     auto startInEditableRoot = firstPositionInNode(root);
209     data.hasContent = root->hasChildNodes() && !isEndOfEditableOrNonEditableContent(startInEditableRoot);
210     data.hasPlainText = data.hasContent && hasAnyPlainText(Range::create(root->document(), VisiblePosition { startInEditableRoot }, VisiblePosition { lastPositionInNode(root) }));
211 }
212
213 bool WebPage::isTransparentOrFullyClipped(const Element& element) const
214 {
215     auto* renderer = element.renderer();
216     if (!renderer)
217         return false;
218
219     auto* enclosingLayer = renderer->enclosingLayer();
220     if (enclosingLayer && enclosingLayer->isTransparentRespectingParentFrames())
221         return true;
222
223     return renderer->hasNonEmptyVisibleRectRespectingParentFrames();
224 }
225
226 bool WebPage::platformNeedsLayoutForEditorState(const Frame& frame) const
227 {
228     // If we have a composition or are using a hardware keyboard then we need to send the full
229     // editor so that the UIProcess can update UI, including the position of the caret.
230     bool needsLayout = frame.editor().hasComposition();
231 #if !PLATFORM(MACCATALYST)
232     needsLayout |= m_keyboardIsAttached;
233 #endif
234     return needsLayout;
235 }
236
237 void WebPage::getPlatformEditorState(Frame& frame, EditorState& result) const
238 {
239     getPlatformEditorStateCommon(frame, result);
240
241     FrameView* view = frame.view();
242     if (!view) {
243         result.isMissingPostLayoutData = true;
244         return;
245     }
246
247     if (frame.editor().hasComposition()) {
248         RefPtr<Range> compositionRange = frame.editor().compositionRange();
249         Vector<WebCore::SelectionRect> compositionRects;
250         if (compositionRange) {
251             compositionRange->collectSelectionRects(compositionRects);
252             if (compositionRects.size())
253                 result.firstMarkedRect = view->contentsToRootView(compositionRects[0].rect());
254             if (compositionRects.size() > 1)
255                 result.lastMarkedRect = view->contentsToRootView(compositionRects.last().rect());
256             else
257                 result.lastMarkedRect = result.firstMarkedRect;
258             result.markedText = plainTextForContext(compositionRange.get());
259         }
260     }
261
262     // We only set the remaining EditorState entries if layout is done as a performance optimization
263     // to avoid the need to force a synchronous layout here to compute these entries. If we
264     // have a composition or are using a hardware keyboard then we send the full editor state
265     // immediately so that the UIProcess can update UI, including the position of the caret.
266     bool needsLayout = view->needsLayout();
267     bool requiresPostLayoutData = frame.editor().hasComposition();
268 #if !PLATFORM(MACCATALYST)
269     requiresPostLayoutData |= m_keyboardIsAttached;
270 #endif
271     if (needsLayout || result.isMissingPostLayoutData)
272         return;
273
274     auto& postLayoutData = result.postLayoutData();
275     const auto& selection = frame.selection().selection();
276     postLayoutData.isStableStateUpdate = m_isInStableState;
277     bool startNodeIsInsideFixedPosition = false;
278     bool endNodeIsInsideFixedPosition = false;
279     if (selection.isCaret()) {
280         postLayoutData.caretRectAtStart = view->contentsToRootView(frame.selection().absoluteCaretBounds(&startNodeIsInsideFixedPosition));
281         endNodeIsInsideFixedPosition = startNodeIsInsideFixedPosition;
282         postLayoutData.caretRectAtEnd = postLayoutData.caretRectAtStart;
283         // FIXME: The following check should take into account writing direction.
284         postLayoutData.isReplaceAllowed = result.isContentEditable && atBoundaryOfGranularity(selection.start(), WordGranularity, DirectionForward);
285         postLayoutData.wordAtSelection = plainTextForContext(wordRangeFromPosition(selection.start()).get());
286         if (selection.isContentEditable())
287             charactersAroundPosition(selection.start(), postLayoutData.characterAfterSelection, postLayoutData.characterBeforeSelection, postLayoutData.twoCharacterBeforeSelection);
288     } else if (selection.isRange()) {
289         postLayoutData.caretRectAtStart = view->contentsToRootView(VisiblePosition(selection.start()).absoluteCaretBounds(&startNodeIsInsideFixedPosition));
290         postLayoutData.caretRectAtEnd = view->contentsToRootView(VisiblePosition(selection.end()).absoluteCaretBounds(&endNodeIsInsideFixedPosition));
291         RefPtr<Range> selectedRange = selection.toNormalizedRange();
292         String selectedText;
293         if (selectedRange) {
294             selectedRange->collectSelectionRects(postLayoutData.selectionRects);
295             convertSelectionRectsToRootView(view, postLayoutData.selectionRects);
296             selectedText = plainTextForDisplay(selectedRange.get());
297             postLayoutData.selectedTextLength = selectedText.length();
298             const int maxSelectedTextLength = 200;
299             postLayoutData.wordAtSelection = selectedText.left(maxSelectedTextLength);
300         }
301         // FIXME: We should disallow replace when the string contains only CJ characters.
302         postLayoutData.isReplaceAllowed = result.isContentEditable && !result.isInPasswordField && !selectedText.isAllSpecialCharacters<isHTMLSpace>();
303     }
304     postLayoutData.atStartOfSentence = frame.selection().selectionAtSentenceStart();
305     postLayoutData.insideFixedPosition = startNodeIsInsideFixedPosition || endNodeIsInsideFixedPosition;
306     if (!selection.isNone()) {
307         if (m_focusedElement && m_focusedElement->renderer()) {
308             auto& renderer = *m_focusedElement->renderer();
309             postLayoutData.focusedElementRect = rootViewInteractionBoundsForElement(*m_focusedElement);
310             postLayoutData.caretColor = CaretBase::computeCaretColor(renderer.style(), renderer.element());
311         }
312         if (result.isContentEditable) {
313             if (auto editableRootOrFormControl = makeRefPtr(selection.rootEditableElement())) {
314                 if (is<HTMLTextFormControlElement>(editableRootOrFormControl->shadowHost()))
315                     editableRootOrFormControl = editableRootOrFormControl->shadowHost();
316                 postLayoutData.editableRootIsTransparentOrFullyClipped = isTransparentOrFullyClipped(*editableRootOrFormControl);
317             }
318         }
319         computeEditableRootHasContentAndPlainText(selection, postLayoutData);
320         postLayoutData.selectionStartIsAtParagraphBoundary = atBoundaryOfGranularity(selection.visibleStart(), TextGranularity::ParagraphGranularity, SelectionDirection::DirectionBackward);
321         postLayoutData.selectionEndIsAtParagraphBoundary = atBoundaryOfGranularity(selection.visibleEnd(), TextGranularity::ParagraphGranularity, SelectionDirection::DirectionForward);
322     }
323 }
324
325 void WebPage::platformWillPerformEditingCommand()
326 {
327     auto& frame = m_page->focusController().focusedOrMainFrame();
328     if (auto* document = frame.document()) {
329         if (auto* holdingTank = document->domTimerHoldingTankIfExists())
330             holdingTank->removeAll();
331     }
332 }
333
334 FloatSize WebPage::screenSize() const
335 {
336     return m_screenSize;
337 }
338
339 FloatSize WebPage::availableScreenSize() const
340 {
341     return m_availableScreenSize;
342 }
343
344 FloatSize WebPage::overrideScreenSize() const
345 {
346     return m_overrideScreenSize;
347 }
348
349 void WebPage::didReceiveMobileDocType(bool isMobileDoctype)
350 {
351     resetViewportDefaultConfiguration(m_mainFrame.ptr(), isMobileDoctype);
352 }
353
354 void WebPage::savePageState(HistoryItem& historyItem)
355 {
356     historyItem.setScaleIsInitial(!m_userHasChangedPageScaleFactor);
357     historyItem.setMinimumLayoutSizeInScrollViewCoordinates(m_viewportConfiguration.minimumLayoutSize());
358     historyItem.setContentSize(m_viewportConfiguration.contentsSize());
359 }
360
361 static double scaleAfterViewportWidthChange(double currentScale, bool userHasChangedPageScaleFactor, const ViewportConfiguration& viewportConfiguration, float unobscuredWidthInScrollViewCoordinates, const IntSize& newContentSize, const IntSize& oldContentSize, float visibleHorizontalFraction)
362 {
363     double scale;
364     if (!userHasChangedPageScaleFactor)
365         scale = viewportConfiguration.initialScale();
366     else
367         scale = std::max(std::min(currentScale, viewportConfiguration.maximumScale()), viewportConfiguration.minimumScale());
368
369     LOG(VisibleRects, "scaleAfterViewportWidthChange getting scale %.2f", scale);
370
371     if (userHasChangedPageScaleFactor) {
372         // When the content size changes, we keep the same relative horizontal content width in view, otherwise we would
373         // end up zoomed too far in landscape->portrait, and too close in portrait->landscape.
374         double widthToKeepInView = visibleHorizontalFraction * newContentSize.width();
375         double newScale = unobscuredWidthInScrollViewCoordinates / widthToKeepInView;
376         scale = std::max(std::min(newScale, viewportConfiguration.maximumScale()), viewportConfiguration.minimumScale());
377     }
378     return scale;
379 }
380
381 static FloatPoint relativeCenterAfterContentSizeChange(const FloatRect& originalContentRect, IntSize oldContentSize, IntSize newContentSize)
382 {
383     // If the content size has changed, keep the same relative position.
384     FloatPoint oldContentCenter = originalContentRect.center();
385     float relativeHorizontalPosition = oldContentCenter.x() / oldContentSize.width();
386     float relativeVerticalPosition =  oldContentCenter.y() / oldContentSize.height();
387     return FloatPoint(relativeHorizontalPosition * newContentSize.width(), relativeVerticalPosition * newContentSize.height());
388 }
389
390 static inline FloatRect adjustExposedRectForNewScale(const FloatRect& exposedRect, double exposedRectScale, double newScale)
391 {
392     if (exposedRectScale == newScale)
393         return exposedRect;
394
395     float horizontalChange = exposedRect.width() * exposedRectScale / newScale - exposedRect.width();
396     float verticalChange = exposedRect.height() * exposedRectScale / newScale - exposedRect.height();
397
398     auto adjustedRect = exposedRect;
399     adjustedRect.inflate({ horizontalChange / 2, verticalChange / 2 });
400     return adjustedRect;
401 }
402
403 void WebPage::restorePageState(const HistoryItem& historyItem)
404 {
405     // When a HistoryItem is cleared, its scale factor and scroll point are set to zero. We should not try to restore the other
406     // parameters in those conditions.
407     if (!historyItem.pageScaleFactor()) {
408         send(Messages::WebPageProxy::CouldNotRestorePageState());
409         return;
410     }
411
412     // We can restore the exposed rect and scale, but we cannot touch the scroll position since the obscured insets
413     // may be changing in the UIProcess. The UIProcess can update the position from the information we send and will then
414     // scroll to the correct position through a regular VisibleContentRectUpdate.
415
416     m_userHasChangedPageScaleFactor = !historyItem.scaleIsInitial();
417
418     FrameView& frameView = *m_page->mainFrame().view();
419
420     FloatSize currentMinimumLayoutSizeInScrollViewCoordinates = m_viewportConfiguration.minimumLayoutSize();
421     if (historyItem.minimumLayoutSizeInScrollViewCoordinates() == currentMinimumLayoutSizeInScrollViewCoordinates) {
422         float boundedScale = historyItem.scaleIsInitial() ? m_viewportConfiguration.initialScale() : historyItem.pageScaleFactor();
423         boundedScale = std::min<float>(m_viewportConfiguration.maximumScale(), std::max<float>(m_viewportConfiguration.minimumScale(), boundedScale));
424         scalePage(boundedScale, IntPoint());
425
426         Optional<FloatPoint> scrollPosition;
427         if (historyItem.shouldRestoreScrollPosition()) {
428             m_drawingArea->setExposedContentRect(historyItem.exposedContentRect());
429             m_hasRestoredExposedContentRectAfterDidCommitLoad = true;
430             scrollPosition = FloatPoint(historyItem.scrollPosition());
431         }
432         send(Messages::WebPageProxy::RestorePageState(scrollPosition, frameView.scrollOrigin(), historyItem.obscuredInsets(), boundedScale));
433     } else {
434         IntSize oldContentSize = historyItem.contentSize();
435         IntSize newContentSize = frameView.contentsSize();
436         double visibleHorizontalFraction = static_cast<float>(historyItem.unobscuredContentRect().width()) / oldContentSize.width();
437
438         double newScale = scaleAfterViewportWidthChange(historyItem.pageScaleFactor(), !historyItem.scaleIsInitial(), m_viewportConfiguration, currentMinimumLayoutSizeInScrollViewCoordinates.width(), newContentSize, oldContentSize, visibleHorizontalFraction);
439
440         Optional<FloatPoint> newCenter;
441         if (historyItem.shouldRestoreScrollPosition()) {
442             if (!oldContentSize.isEmpty() && !newContentSize.isEmpty() && newContentSize != oldContentSize)
443                 newCenter = relativeCenterAfterContentSizeChange(historyItem.unobscuredContentRect(), oldContentSize, newContentSize);
444             else
445                 newCenter = FloatRect(historyItem.unobscuredContentRect()).center();
446         }
447
448         scalePage(newScale, IntPoint());
449         send(Messages::WebPageProxy::RestorePageCenterAndScale(newCenter, newScale));
450     }
451 }
452
453 double WebPage::minimumPageScaleFactor() const
454 {
455     if (!m_viewportConfiguration.allowsUserScaling())
456         return m_page->pageScaleFactor();
457     return m_viewportConfiguration.minimumScale();
458 }
459
460 double WebPage::maximumPageScaleFactor() const
461 {
462     if (!m_viewportConfiguration.allowsUserScaling())
463         return m_page->pageScaleFactor();
464     return m_viewportConfiguration.maximumScale();
465 }
466
467 double WebPage::maximumPageScaleFactorIgnoringAlwaysScalable() const
468 {
469     if (!m_viewportConfiguration.allowsUserScalingIgnoringAlwaysScalable())
470         return m_page->pageScaleFactor();
471     return m_viewportConfiguration.maximumScaleIgnoringAlwaysScalable();
472 }
473
474 bool WebPage::allowsUserScaling() const
475 {
476     return m_viewportConfiguration.allowsUserScaling();
477 }
478
479 bool WebPage::handleEditingKeyboardEvent(KeyboardEvent& event)
480 {
481     auto* platformEvent = event.underlyingPlatformEvent();
482     if (!platformEvent)
483         return false;
484     
485     // Don't send synthetic events to the UIProcess. They are only
486     // used for interacting with JavaScript.
487     if (platformEvent->isSyntheticEvent())
488         return false;
489
490     // FIXME: Interpret the event immediately upon receiving it in UI process, without sending to WebProcess first.
491     bool eventWasHandled = false;
492     bool sendResult = WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPageProxy::InterpretKeyEvent(editorState(ShouldPerformLayout::Yes), platformEvent->type() == PlatformKeyboardEvent::Char),
493         Messages::WebPageProxy::InterpretKeyEvent::Reply(eventWasHandled), m_identifier);
494     return sendResult && eventWasHandled;
495 }
496
497 bool WebPage::parentProcessHasServiceWorkerEntitlement() const
498 {
499     static bool hasEntitlement = WTF::hasEntitlement(WebProcess::singleton().parentProcessConnection()->xpcConnection(), "com.apple.developer.WebKit.ServiceWorkers");
500     return hasEntitlement;
501 }
502
503 void WebPage::sendComplexTextInputToPlugin(uint64_t, const String&)
504 {
505     notImplemented();
506 }
507
508 bool WebPage::performNonEditingBehaviorForSelector(const String&, WebCore::KeyboardEvent*)
509 {
510     notImplemented();
511     return false;
512 }
513
514 bool WebPage::performDefaultBehaviorForKeyEvent(const WebKeyboardEvent&)
515 {
516     notImplemented();
517     return false;
518 }
519
520 void WebPage::getSelectionContext(CallbackID callbackID)
521 {
522     Frame& frame = m_page->focusController().focusedOrMainFrame();
523     if (!frame.selection().isRange()) {
524         send(Messages::WebPageProxy::SelectionContextCallback(String(), String(), String(), callbackID));
525         return;
526     }
527     const int selectionExtendedContextLength = 350;
528     
529     String selectedText = plainTextForContext(frame.selection().selection().toNormalizedRange().get());
530     String textBefore = plainTextForDisplay(rangeExpandedByCharactersInDirectionAtWordBoundary(frame.selection().selection().start(), selectionExtendedContextLength, DirectionBackward).get());
531     String textAfter = plainTextForDisplay(rangeExpandedByCharactersInDirectionAtWordBoundary(frame.selection().selection().end(), selectionExtendedContextLength, DirectionForward).get());
532
533     send(Messages::WebPageProxy::SelectionContextCallback(selectedText, textBefore, textAfter, callbackID));
534 }
535
536 NSObject *WebPage::accessibilityObjectForMainFramePlugin()
537 {
538     if (!m_page)
539         return nil;
540     
541     if (auto* pluginView = pluginViewForFrame(&m_page->mainFrame()))
542         return pluginView->accessibilityObject();
543     
544     return nil;
545 }
546     
547 void WebPage::registerUIProcessAccessibilityTokens(const IPC::DataReference& elementToken, const IPC::DataReference&)
548 {
549     NSData *elementTokenData = [NSData dataWithBytes:elementToken.data() length:elementToken.size()];
550     [m_mockAccessibilityElement setRemoteTokenData:elementTokenData];
551 }
552
553 void WebPage::readSelectionFromPasteboard(const String&, CompletionHandler<void(bool&&)>&& completionHandler)
554 {
555     notImplemented();
556     completionHandler(false);
557 }
558
559 void WebPage::getStringSelectionForPasteboard(CompletionHandler<void(String&&)>&& completionHandler)
560 {
561     notImplemented();
562     completionHandler({ });
563 }
564
565 void WebPage::getDataSelectionForPasteboard(const String, CompletionHandler<void(SharedMemory::Handle&&, uint64_t)>&& completionHandler)
566 {
567     notImplemented();
568     completionHandler({ }, 0);
569 }
570
571 WKAccessibilityWebPageObject* WebPage::accessibilityRemoteObject()
572 {
573     notImplemented();
574     return 0;
575 }
576
577 bool WebPage::platformCanHandleRequest(const WebCore::ResourceRequest&)
578 {
579     notImplemented();
580     return false;
581 }
582
583 void WebPage::shouldDelayWindowOrderingEvent(const WebKit::WebMouseEvent&, CompletionHandler<void(bool)>&& completionHandler)
584 {
585     notImplemented();
586     completionHandler(false);
587 }
588
589 void WebPage::acceptsFirstMouse(int, const WebKit::WebMouseEvent&, CompletionHandler<void(bool)>&& completionHandler)
590 {
591     notImplemented();
592     completionHandler(false);
593 }
594
595 void WebPage::computePagesForPrintingPDFDocument(WebCore::FrameIdentifier, const PrintInfo&, Vector<IntRect>&)
596 {
597     notImplemented();
598 }
599
600 void WebPage::drawPagesToPDFFromPDFDocument(CGContextRef, PDFDocument *, const PrintInfo&, uint32_t, uint32_t)
601 {
602     notImplemented();
603 }
604
605 void WebPage::advanceToNextMisspelling(bool)
606 {
607     notImplemented();
608 }
609
610 IntRect WebPage::rectForElementAtInteractionLocation() const
611 {
612     constexpr OptionSet<HitTestRequest::RequestType> hitType { HitTestRequest::ReadOnly, HitTestRequest::Active, HitTestRequest::AllowVisibleChildFrameContentOnly };
613     HitTestResult result = m_page->mainFrame().eventHandler().hitTestResultAtPoint(m_lastInteractionLocation, hitType);
614     Node* hitNode = result.innerNode();
615     if (!hitNode || !hitNode->renderer())
616         return IntRect();
617     return result.innerNodeFrame()->view()->contentsToRootView(hitNode->renderer()->absoluteBoundingBoxRect(true));
618 }
619
620 void WebPage::updateSelectionAppearance()
621 {
622     auto& frame = m_page->focusController().focusedOrMainFrame();
623     auto& editor = frame.editor();
624     if (editor.ignoreSelectionChanges())
625         return;
626
627     if (editor.client() && !editor.client()->shouldRevealCurrentSelectionAfterInsertion())
628         return;
629
630     if (!editor.hasComposition() && frame.selection().selection().isNone())
631         return;
632
633     didChangeSelection();
634 }
635
636 static void dispatchSyntheticMouseMove(Frame& mainFrame, const WebCore::FloatPoint& location, OptionSet<WebEvent::Modifier> modifiers, WebCore::PointerID pointerId = WebCore::mousePointerID)
637 {
638     IntPoint roundedAdjustedPoint = roundedIntPoint(location);
639     auto shiftKey = modifiers.contains(WebEvent::Modifier::ShiftKey);
640     auto ctrlKey = modifiers.contains(WebEvent::Modifier::ControlKey);
641     auto altKey = modifiers.contains(WebEvent::Modifier::AltKey);
642     auto metaKey = modifiers.contains(WebEvent::Modifier::MetaKey);
643     auto mouseEvent = PlatformMouseEvent(roundedAdjustedPoint, roundedAdjustedPoint, NoButton, PlatformEvent::MouseMoved, 0, shiftKey, ctrlKey, altKey, metaKey, WallTime::now(), WebCore::ForceAtClick, WebCore::NoTap, pointerId);
644     // FIXME: Pass caps lock state.
645     mainFrame.eventHandler().dispatchSyntheticMouseMove(mouseEvent);
646 }
647
648 void WebPage::generateSyntheticEditingCommand(SyntheticEditingCommandType command)
649 {
650     PlatformKeyboardEvent keyEvent;
651     auto& frame = m_page->focusController().focusedOrMainFrame();
652     
653     OptionSet<PlatformEvent::Modifier> modifiers;
654     modifiers.add(PlatformEvent::Modifier::MetaKey);
655     
656     switch (command) {
657     case SyntheticEditingCommandType::Undo:
658         keyEvent = PlatformKeyboardEvent(PlatformEvent::KeyDown, "z", "z",
659         "z", "KeyZ"_s,
660         @"U+005A", 90, false, false, false, modifiers, WallTime::now());
661         break;
662     case SyntheticEditingCommandType::Redo:
663         keyEvent = PlatformKeyboardEvent(PlatformEvent::KeyDown, "y", "y",
664         "y", "KeyY"_s,
665         @"U+0059", 89, false, false, false, modifiers, WallTime::now());
666         break;
667     case SyntheticEditingCommandType::ToggleBoldface:
668         keyEvent = PlatformKeyboardEvent(PlatformEvent::KeyDown, "b", "b",
669         "b", "KeyB"_s,
670         @"U+0042", 66, false, false, false, modifiers, WallTime::now());
671         break;
672     case SyntheticEditingCommandType::ToggleItalic:
673         keyEvent = PlatformKeyboardEvent(PlatformEvent::KeyDown, "i", "i",
674         "i", "KeyI"_s,
675         @"U+0049", 73, false, false, false, modifiers, WallTime::now());
676         break;
677     case SyntheticEditingCommandType::ToggleUnderline:
678         keyEvent = PlatformKeyboardEvent(PlatformEvent::KeyDown, "u", "u",
679         "u", "KeyU"_s,
680         @"U+0055", 85, false, false, false, modifiers, WallTime::now());
681         break;
682     default:
683         break;
684     }
685
686     keyEvent.setIsSyntheticEvent();
687     
688     PlatformKeyboardEvent::setCurrentModifierState(modifiers);
689     
690     frame.eventHandler().keyEvent(keyEvent);
691 }
692
693 void WebPage::handleSyntheticClick(Node& nodeRespondingToClick, const WebCore::FloatPoint& location, OptionSet<WebEvent::Modifier> modifiers, WebCore::PointerID pointerId)
694 {
695     if (!nodeRespondingToClick.document().settings().contentChangeObserverEnabled()) {
696         completeSyntheticClick(nodeRespondingToClick, location, modifiers, WebCore::OneFingerTap, pointerId);
697         return;
698     }
699
700     auto& respondingDocument = nodeRespondingToClick.document();
701     auto& contentChangeObserver = respondingDocument.contentChangeObserver();
702     auto targetNodeWentFromHiddenToVisible = contentChangeObserver.hiddenTouchTarget() == &nodeRespondingToClick && ContentChangeObserver::isConsideredVisible(nodeRespondingToClick);
703     {
704         LOG_WITH_STREAM(ContentObservation, stream << "handleSyntheticClick: node(" << &nodeRespondingToClick << ") " << location);
705         ContentChangeObserver::MouseMovedScope observingScope(respondingDocument);
706         auto& mainFrame = m_page->mainFrame();
707         dispatchSyntheticMouseMove(mainFrame, location, modifiers, pointerId);
708         mainFrame.document()->updateStyleIfNeeded();
709         if (m_isClosed)
710             return;
711     }
712
713     if (targetNodeWentFromHiddenToVisible) {
714         LOG(ContentObservation, "handleSyntheticClick: target node was hidden and now is visible -> hover.");
715         return;
716     }
717
718     auto nodeTriggersFastPath = [&](auto& targetNode) {
719         if (!is<Element>(targetNode))
720             return false;
721         if (is<HTMLFormControlElement>(targetNode))
722             return true;
723         if (targetNode.document().quirks().shouldIgnoreAriaForFastPathContentObservationCheck())
724             return false;
725         auto ariaRole = AccessibilityObject::ariaRoleToWebCoreRole(downcast<Element>(targetNode).getAttribute(HTMLNames::roleAttr));
726         return AccessibilityObject::isARIAControl(ariaRole) || AccessibilityObject::isARIAInput(ariaRole);
727     };
728     auto targetNodeTriggersFastPath = nodeTriggersFastPath(nodeRespondingToClick);
729
730     auto observedContentChange = contentChangeObserver.observedContentChange();
731     auto continueContentObservation = !(observedContentChange == WKContentVisibilityChange || targetNodeTriggersFastPath);
732     if (continueContentObservation) {
733         // Wait for callback to completePendingSyntheticClickForContentChangeObserver() to decide whether to send the click event.
734         const Seconds observationDuration = 32_ms;
735         contentChangeObserver.startContentObservationForDuration(observationDuration);
736         LOG(ContentObservation, "handleSyntheticClick: Can't decide it yet -> wait.");
737         m_pendingSyntheticClickNode = &nodeRespondingToClick;
738         m_pendingSyntheticClickLocation = location;
739         m_pendingSyntheticClickModifiers = modifiers;
740         m_pendingSyntheticClickPointerId = pointerId;
741         return;
742     }
743     contentChangeObserver.stopContentObservation();
744     callOnMainThread([protectedThis = makeRefPtr(this), targetNode = Ref<Node>(nodeRespondingToClick), location, modifiers, observedContentChange, pointerId] {
745         if (protectedThis->m_isClosed || !protectedThis->corePage())
746             return;
747
748         auto shouldStayAtHoverState = observedContentChange == WKContentVisibilityChange;
749         if (shouldStayAtHoverState) {
750             // The move event caused new contents to appear. Don't send synthetic click event, but just ensure that the mouse is on the most recent content.
751             dispatchSyntheticMouseMove(protectedThis->corePage()->mainFrame(), location, modifiers, pointerId);
752             LOG(ContentObservation, "handleSyntheticClick: Observed meaningful visible change -> hover.");
753             return;
754         }
755         LOG(ContentObservation, "handleSyntheticClick: calling completeSyntheticClick -> click.");
756         protectedThis->completeSyntheticClick(targetNode, location, modifiers, WebCore::OneFingerTap, pointerId);
757     });
758 }
759
760 void WebPage::didFinishContentChangeObserving(WKContentChange observedContentChange)
761 {
762     LOG_WITH_STREAM(ContentObservation, stream << "didFinishContentChangeObserving: pending target node(" << m_pendingSyntheticClickNode << ")");
763     if (!m_pendingSyntheticClickNode)
764         return;
765     callOnMainThread([protectedThis = makeRefPtr(this), targetNode = Ref<Node>(*m_pendingSyntheticClickNode), originalDocument = makeWeakPtr(m_pendingSyntheticClickNode->document()), observedContentChange, location = m_pendingSyntheticClickLocation, modifiers = m_pendingSyntheticClickModifiers, pointerId = m_pendingSyntheticClickPointerId] {
766         if (protectedThis->m_isClosed || !protectedThis->corePage())
767             return;
768         if (!originalDocument || &targetNode->document() != originalDocument)
769             return;
770
771         // Only dispatch the click if the document didn't get changed by any timers started by the move event.
772         if (observedContentChange == WKContentNoChange) {
773             LOG(ContentObservation, "No chage was observed -> click.");
774             protectedThis->completeSyntheticClick(targetNode, location, modifiers, WebCore::OneFingerTap, pointerId);
775             return;
776         }
777         // Ensure that the mouse is on the most recent content.
778         LOG(ContentObservation, "Observed meaningful visible change -> hover.");
779         dispatchSyntheticMouseMove(protectedThis->corePage()->mainFrame(), location, modifiers, pointerId);
780     });
781     m_pendingSyntheticClickNode = nullptr;
782     m_pendingSyntheticClickLocation = { };
783     m_pendingSyntheticClickModifiers = { };
784     m_pendingSyntheticClickPointerId = 0;
785 }
786
787 void WebPage::completeSyntheticClick(Node& nodeRespondingToClick, const WebCore::FloatPoint& location, OptionSet<WebEvent::Modifier> modifiers, SyntheticClickType syntheticClickType, WebCore::PointerID pointerId)
788 {
789     IntPoint roundedAdjustedPoint = roundedIntPoint(location);
790     Frame& mainframe = m_page->mainFrame();
791
792     RefPtr<Frame> oldFocusedFrame = m_page->focusController().focusedFrame();
793     RefPtr<Element> oldFocusedElement = oldFocusedFrame ? oldFocusedFrame->document()->focusedElement() : nullptr;
794
795     SetForScope<bool> userIsInteractingChange { m_userIsInteracting, true };
796
797     bool tapWasHandled = false;
798     m_lastInteractionLocation = roundedAdjustedPoint;
799
800     // FIXME: Pass caps lock state.
801     bool shiftKey = modifiers.contains(WebEvent::Modifier::ShiftKey);
802     bool ctrlKey = modifiers.contains(WebEvent::Modifier::ControlKey);
803     bool altKey = modifiers.contains(WebEvent::Modifier::AltKey);
804     bool metaKey = modifiers.contains(WebEvent::Modifier::MetaKey);
805
806     tapWasHandled |= mainframe.eventHandler().handleMousePressEvent(PlatformMouseEvent(roundedAdjustedPoint, roundedAdjustedPoint, LeftButton, PlatformEvent::MousePressed, 1, shiftKey, ctrlKey, altKey, metaKey, WallTime::now(), WebCore::ForceAtClick, syntheticClickType, pointerId));
807     if (m_isClosed)
808         return;
809
810     tapWasHandled |= mainframe.eventHandler().handleMouseReleaseEvent(PlatformMouseEvent(roundedAdjustedPoint, roundedAdjustedPoint, LeftButton, PlatformEvent::MouseReleased, 1, shiftKey, ctrlKey, altKey, metaKey, WallTime::now(), WebCore::ForceAtClick, syntheticClickType, pointerId));
811     if (m_isClosed)
812         return;
813
814     RefPtr<Frame> newFocusedFrame = m_page->focusController().focusedFrame();
815     RefPtr<Element> newFocusedElement = newFocusedFrame ? newFocusedFrame->document()->focusedElement() : nullptr;
816
817     // If the focus has not changed, we need to notify the client anyway, since it might be
818     // necessary to start assisting the node.
819     // If the node has been focused by JavaScript without user interaction, the
820     // keyboard is not on screen.
821     if (newFocusedElement && newFocusedElement == oldFocusedElement)
822         elementDidRefocus(*newFocusedElement);
823
824     if (nodeRespondingToClick.document().settings().contentChangeObserverEnabled()) {
825         auto& document = nodeRespondingToClick.document();
826         // Dispatch mouseOut to dismiss tooltip content when tapping on the control bar buttons (cc, settings).
827         if (document.quirks().needsYouTubeMouseOutQuirk()) {
828             if (auto* frame = document.frame())
829                 frame->eventHandler().dispatchSyntheticMouseOut(PlatformMouseEvent(roundedAdjustedPoint, roundedAdjustedPoint, LeftButton, PlatformEvent::NoType, 0, shiftKey, ctrlKey, altKey, metaKey, WallTime::now(), 0, WebCore::NoTap, pointerId));
830         }
831     }
832
833     if (m_isClosed)
834         return;
835
836     if (!tapWasHandled || !nodeRespondingToClick.isElementNode())
837         send(Messages::WebPageProxy::DidNotHandleTapAsClick(roundedIntPoint(location)));
838     
839     send(Messages::WebPageProxy::DidCompleteSyntheticClick());
840 }
841
842 void WebPage::handleTap(const IntPoint& point, OptionSet<WebEvent::Modifier> modifiers, TransactionID lastLayerTreeTransactionId)
843 {
844     FloatPoint adjustedPoint;
845     Node* nodeRespondingToClick = m_page->mainFrame().nodeRespondingToClickEvents(point, adjustedPoint);
846     Frame* frameRespondingToClick = nodeRespondingToClick ? nodeRespondingToClick->document().frame() : nullptr;
847     IntPoint adjustedIntPoint = roundedIntPoint(adjustedPoint);
848
849     if (!frameRespondingToClick || lastLayerTreeTransactionId < WebFrame::fromCoreFrame(*frameRespondingToClick)->firstLayerTreeTransactionIDAfterDidCommitLoad())
850         send(Messages::WebPageProxy::DidNotHandleTapAsClick(adjustedIntPoint));
851 #if ENABLE(DATA_DETECTION)
852     else if (is<Element>(*nodeRespondingToClick) && DataDetection::shouldCancelDefaultAction(downcast<Element>(*nodeRespondingToClick))) {
853         InteractionInformationRequest request(adjustedIntPoint);
854         requestPositionInformation(request);
855         send(Messages::WebPageProxy::DidNotHandleTapAsClick(adjustedIntPoint));
856     }
857 #endif
858     else
859         handleSyntheticClick(*nodeRespondingToClick, adjustedPoint, modifiers);
860 }
861
862 void WebPage::handleDoubleTapForDoubleClickAtPoint(const IntPoint& point, OptionSet<WebEvent::Modifier> modifiers, TransactionID lastLayerTreeTransactionId)
863 {
864     FloatPoint adjustedPoint;
865     auto* nodeRespondingToDoubleClick = m_page->mainFrame().nodeRespondingToDoubleClickEvent(point, adjustedPoint);
866     if (!nodeRespondingToDoubleClick)
867         return;
868
869     auto* frameRespondingToDoubleClick = nodeRespondingToDoubleClick->document().frame();
870     if (!frameRespondingToDoubleClick || lastLayerTreeTransactionId < WebFrame::fromCoreFrame(*frameRespondingToDoubleClick)->firstLayerTreeTransactionIDAfterDidCommitLoad())
871         return;
872
873     bool shiftKey = modifiers.contains(WebEvent::Modifier::ShiftKey);
874     bool ctrlKey = modifiers.contains(WebEvent::Modifier::ControlKey);
875     bool altKey = modifiers.contains(WebEvent::Modifier::AltKey);
876     bool metaKey = modifiers.contains(WebEvent::Modifier::MetaKey);
877     auto roundedAdjustedPoint = roundedIntPoint(adjustedPoint);
878     nodeRespondingToDoubleClick->document().frame()->eventHandler().handleMousePressEvent(PlatformMouseEvent(roundedAdjustedPoint, roundedAdjustedPoint, LeftButton, PlatformEvent::MousePressed, 2, shiftKey, ctrlKey, altKey, metaKey, WallTime::now(), 0, WebCore::OneFingerTap));
879     if (m_isClosed)
880         return;
881     nodeRespondingToDoubleClick->document().frame()->eventHandler().handleMouseReleaseEvent(PlatformMouseEvent(roundedAdjustedPoint, roundedAdjustedPoint, LeftButton, PlatformEvent::MouseReleased, 2, shiftKey, ctrlKey, altKey, metaKey, WallTime::now(), 0, WebCore::OneFingerTap));
882 }
883
884 void WebPage::requestFocusedElementInformation(WebKit::CallbackID callbackID)
885 {
886     FocusedElementInformation info;
887     if (m_focusedElement)
888         getFocusedElementInformation(info);
889
890     send(Messages::WebPageProxy::FocusedElementInformationCallback(info, callbackID));
891 }
892
893 #if ENABLE(DATA_INTERACTION)
894 void WebPage::requestDragStart(const IntPoint& clientPosition, const IntPoint& globalPosition, uint64_t allowedActions)
895 {
896     SetForScope<WebCore::DragSourceAction> allowedActionsForScope(m_allowedDragSourceActions, static_cast<WebCore::DragSourceAction>(allowedActions));
897     bool didStart = m_page->mainFrame().eventHandler().tryToBeginDragAtPoint(clientPosition, globalPosition);
898     send(Messages::WebPageProxy::DidHandleDragStartRequest(didStart));
899 }
900
901 void WebPage::requestAdditionalItemsForDragSession(const IntPoint& clientPosition, const IntPoint& globalPosition, uint64_t allowedActions)
902 {
903     SetForScope<WebCore::DragSourceAction> allowedActionsForScope(m_allowedDragSourceActions, static_cast<WebCore::DragSourceAction>(allowedActions));
904     // To augment the platform drag session with additional items, end the current drag session and begin a new drag session with the new drag item.
905     // This process is opaque to the UI process, which still maintains the old drag item in its drag session. Similarly, this persistent drag session
906     // is opaque to the web process, which only sees that the current drag has ended, and that a new one is beginning.
907     PlatformMouseEvent event(clientPosition, globalPosition, LeftButton, PlatformEvent::MouseMoved, 0, false, false, false, false, WallTime::now(), 0, NoTap);
908     m_page->dragController().dragEnded();
909     m_page->mainFrame().eventHandler().dragSourceEndedAt(event, DragOperationNone, MayExtendDragSession::Yes);
910
911     bool didHandleDrag = m_page->mainFrame().eventHandler().tryToBeginDragAtPoint(clientPosition, globalPosition);
912     send(Messages::WebPageProxy::DidHandleAdditionalDragItemsRequest(didHandleDrag));
913 }
914
915 void WebPage::insertDroppedImagePlaceholders(const Vector<IntSize>& imageSizes, CompletionHandler<void(const Vector<IntRect>&, Optional<WebCore::TextIndicatorData>)>&& reply)
916 {
917     m_page->dragController().insertDroppedImagePlaceholdersAtCaret(imageSizes);
918     auto placeholderRects = m_page->dragController().droppedImagePlaceholders().map([&] (auto& element) {
919         return rootViewBoundsForElement(element);
920     });
921
922     auto imagePlaceholderRange = m_page->dragController().droppedImagePlaceholderRange();
923     if (placeholderRects.size() != imageSizes.size()) {
924         RELEASE_LOG(DragAndDrop, "Failed to insert dropped image placeholders: placeholder rect count (%tu) does not match image size count (%tu).", placeholderRects.size(), imageSizes.size());
925         reply({ }, WTF::nullopt);
926         return;
927     }
928
929     if (!imagePlaceholderRange) {
930         RELEASE_LOG(DragAndDrop, "Failed to insert dropped image placeholders: no image placeholder range.");
931         reply({ }, WTF::nullopt);
932         return;
933     }
934
935     Optional<TextIndicatorData> textIndicatorData;
936     OptionSet<TextIndicatorOption> textIndicatorOptions = {
937         TextIndicatorOptionIncludeSnapshotOfAllVisibleContentWithoutSelection,
938         TextIndicatorOptionExpandClipBeyondVisibleRect,
939         TextIndicatorOptionPaintAllContent,
940         TextIndicatorOptionUseSelectionRectForSizing
941     };
942
943     if (auto textIndicator = TextIndicator::createWithRange(*imagePlaceholderRange, textIndicatorOptions.toRaw(), TextIndicatorPresentationTransition::None, { }))
944         textIndicatorData = textIndicator->data();
945
946     reply(WTFMove(placeholderRects), WTFMove(textIndicatorData));
947 }
948
949 void WebPage::didConcludeDrop()
950 {
951     m_rangeForDropSnapshot = nullptr;
952     m_pendingImageElementsForDropSnapshot.clear();
953 }
954
955 void WebPage::didConcludeEditDrag()
956 {
957     send(Messages::WebPageProxy::WillReceiveEditDragSnapshot());
958
959     layoutIfNeeded();
960
961     m_pendingImageElementsForDropSnapshot.clear();
962
963     auto frame = makeRef(m_page->focusController().focusedOrMainFrame());
964     if (auto selectionRange = frame->selection().selection().toNormalizedRange()) {
965         m_pendingImageElementsForDropSnapshot = visibleImageElementsInRangeWithNonLoadedImages(*selectionRange);
966         auto collapsedRange = Range::create(selectionRange->ownerDocument(), selectionRange->endPosition(), selectionRange->endPosition());
967         frame->selection().setSelectedRange(collapsedRange.ptr(), DOWNSTREAM, FrameSelection::ShouldCloseTyping::Yes, UserTriggered);
968
969         m_rangeForDropSnapshot = WTFMove(selectionRange);
970     }
971
972     if (m_pendingImageElementsForDropSnapshot.isEmpty())
973         computeAndSendEditDragSnapshot();
974 }
975
976 void WebPage::didFinishLoadingImageForElement(WebCore::HTMLImageElement& element)
977 {
978     if (element.isDroppedImagePlaceholder())
979         m_page->dragController().finalizeDroppedImagePlaceholder(element);
980
981     if (m_pendingImageElementsForDropSnapshot.isEmpty())
982         return;
983
984     m_pendingImageElementsForDropSnapshot.remove(&element);
985
986     if (m_pendingImageElementsForDropSnapshot.isEmpty())
987         computeAndSendEditDragSnapshot();
988 }
989
990 void WebPage::computeAndSendEditDragSnapshot()
991 {
992     Optional<TextIndicatorData> textIndicatorData;
993     static auto defaultTextIndicatorOptionsForEditDrag = TextIndicatorOptionIncludeSnapshotOfAllVisibleContentWithoutSelection | TextIndicatorOptionExpandClipBeyondVisibleRect | TextIndicatorOptionPaintAllContent | TextIndicatorOptionIncludeMarginIfRangeMatchesSelection | TextIndicatorOptionPaintBackgrounds | TextIndicatorOptionComputeEstimatedBackgroundColor | TextIndicatorOptionUseSelectionRectForSizing | TextIndicatorOptionIncludeSnapshotWithSelectionHighlight;
994     if (auto range = std::exchange(m_rangeForDropSnapshot, nullptr)) {
995         if (auto textIndicator = TextIndicator::createWithRange(*range, defaultTextIndicatorOptionsForEditDrag, TextIndicatorPresentationTransition::None, { }))
996             textIndicatorData = textIndicator->data();
997     }
998     send(Messages::WebPageProxy::DidReceiveEditDragSnapshot(WTFMove(textIndicatorData)));
999 }
1000
1001 #endif
1002
1003 void WebPage::sendTapHighlightForNodeIfNecessary(uint64_t requestID, Node* node)
1004 {
1005 #if ENABLE(TOUCH_EVENTS)
1006     if (!node)
1007         return;
1008
1009     if (m_page->isEditable() && node == m_page->mainFrame().document()->body())
1010         return;
1011
1012     if (is<Element>(*node)) {
1013         ASSERT(m_page);
1014         m_page->mainFrame().loader().client().prefetchDNS(downcast<Element>(*node).absoluteLinkURL().host().toString());
1015     }
1016
1017     if (is<HTMLAreaElement>(node)) {
1018         node = downcast<HTMLAreaElement>(node)->imageElement();
1019         if (!node)
1020             return;
1021     }
1022
1023     Vector<FloatQuad> quads;
1024     if (RenderObject *renderer = node->renderer()) {
1025         renderer->absoluteQuads(quads);
1026         Color highlightColor = renderer->style().tapHighlightColor();
1027         if (!node->document().frame()->isMainFrame()) {
1028             FrameView* view = node->document().frame()->view();
1029             for (size_t i = 0; i < quads.size(); ++i) {
1030                 FloatQuad& currentQuad = quads[i];
1031                 currentQuad.setP1(view->contentsToRootView(roundedIntPoint(currentQuad.p1())));
1032                 currentQuad.setP2(view->contentsToRootView(roundedIntPoint(currentQuad.p2())));
1033                 currentQuad.setP3(view->contentsToRootView(roundedIntPoint(currentQuad.p3())));
1034                 currentQuad.setP4(view->contentsToRootView(roundedIntPoint(currentQuad.p4())));
1035             }
1036         }
1037
1038         RoundedRect::Radii borderRadii;
1039         if (is<RenderBox>(*renderer))
1040             borderRadii = downcast<RenderBox>(*renderer).borderRadii();
1041
1042         bool nodeHasBuiltInClickHandling = is<HTMLFormControlElement>(*node) || is<HTMLAnchorElement>(*node) || is<HTMLLabelElement>(*node) || is<HTMLSummaryElement>(*node) || node->isLink();
1043         send(Messages::WebPageProxy::DidGetTapHighlightGeometries(requestID, highlightColor, quads, roundedIntSize(borderRadii.topLeft()), roundedIntSize(borderRadii.topRight()), roundedIntSize(borderRadii.bottomLeft()), roundedIntSize(borderRadii.bottomRight()), nodeHasBuiltInClickHandling));
1044     }
1045 #else
1046     UNUSED_PARAM(requestID);
1047     UNUSED_PARAM(node);
1048 #endif
1049 }
1050
1051 void WebPage::handleTwoFingerTapAtPoint(const WebCore::IntPoint& point, OptionSet<WebKit::WebEvent::Modifier> modifiers, uint64_t requestID)
1052 {
1053     FloatPoint adjustedPoint;
1054     Node* nodeRespondingToClick = m_page->mainFrame().nodeRespondingToClickEvents(point, adjustedPoint);
1055     if (!nodeRespondingToClick || !nodeRespondingToClick->renderer()) {
1056         send(Messages::WebPageProxy::DidNotHandleTapAsClick(roundedIntPoint(adjustedPoint)));
1057         return;
1058     }
1059     sendTapHighlightForNodeIfNecessary(requestID, nodeRespondingToClick);
1060 #if ENABLE(DATA_DETECTION)
1061     if (is<Element>(*nodeRespondingToClick) && DataDetection::shouldCancelDefaultAction(downcast<Element>(*nodeRespondingToClick))) {
1062         InteractionInformationRequest request(roundedIntPoint(adjustedPoint));
1063         requestPositionInformation(request);
1064         send(Messages::WebPageProxy::DidNotHandleTapAsClick(roundedIntPoint(adjustedPoint)));
1065     } else
1066 #endif
1067         completeSyntheticClick(*nodeRespondingToClick, adjustedPoint, modifiers, WebCore::TwoFingerTap);
1068 }
1069
1070 void WebPage::handleStylusSingleTapAtPoint(const WebCore::IntPoint& point, uint64_t requestID)
1071 {
1072     SetForScope<bool> userIsInteractingChange { m_userIsInteracting, true };
1073
1074     auto& frame = m_page->focusController().focusedOrMainFrame();
1075
1076     auto pointInDocument = frame.view()->rootViewToContents(point);
1077     constexpr OptionSet<HitTestRequest::RequestType> hitType { HitTestRequest::ReadOnly, HitTestRequest::Active, HitTestRequest::AllowVisibleChildFrameContentOnly };
1078     HitTestResult hitTest = frame.eventHandler().hitTestResultAtPoint(pointInDocument, hitType);
1079
1080     Node* node = hitTest.innerNonSharedNode();
1081     if (!node)
1082         return;
1083     auto renderer = node->renderer();
1084     if (!renderer)
1085         return;
1086
1087     if (renderer->isReplaced())
1088         return;
1089
1090     VisiblePosition position = renderer->positionForPoint(hitTest.localPoint(), nullptr);
1091     if (position.isNull())
1092         position = firstPositionInOrBeforeNode(node);
1093
1094     if (position.isNull())
1095         return;
1096
1097     auto range = Range::create(*frame.document(), position, position);
1098     frame.selection().setSelectedRange(range.ptr(), position.affinity(), WebCore::FrameSelection::ShouldCloseTyping::Yes, UserTriggered);
1099     auto image = frame.editor().insertEditableImage();
1100     frame.document()->setFocusedElement(image.get());
1101 }
1102
1103 void WebPage::potentialTapAtPosition(uint64_t requestID, const WebCore::FloatPoint& position, bool shouldRequestMagnificationInformation)
1104 {
1105     m_potentialTapNode = m_page->mainFrame().nodeRespondingToClickEvents(position, m_potentialTapLocation, m_potentialTapSecurityOrigin.get());
1106
1107     if (shouldRequestMagnificationInformation && m_potentialTapNode && m_viewGestureGeometryCollector) {
1108         // FIXME: Could this be combined into tap highlight?
1109         FloatPoint origin = position;
1110         FloatRect renderRect;
1111         bool fitEntireRect;
1112         double viewportMinimumScale;
1113         double viewportMaximumScale;
1114
1115         m_viewGestureGeometryCollector->computeZoomInformationForNode(*m_potentialTapNode, origin, renderRect, fitEntireRect, viewportMinimumScale, viewportMaximumScale);
1116
1117         bool nodeIsRootLevel = is<WebCore::Document>(*m_potentialTapNode) || is<WebCore::HTMLBodyElement>(*m_potentialTapNode);
1118         send(Messages::WebPageProxy::HandleSmartMagnificationInformationForPotentialTap(requestID, renderRect, fitEntireRect, viewportMinimumScale, viewportMaximumScale, nodeIsRootLevel));
1119     }
1120
1121     sendTapHighlightForNodeIfNecessary(requestID, m_potentialTapNode.get());
1122 #if ENABLE(TOUCH_EVENTS)
1123     if (m_potentialTapNode && !m_potentialTapNode->allowsDoubleTapGesture())
1124         send(Messages::WebPageProxy::DisableDoubleTapGesturesDuringTapIfNecessary(requestID));
1125 #endif
1126 }
1127
1128 void WebPage::commitPotentialTap(OptionSet<WebEvent::Modifier> modifiers, TransactionID lastLayerTreeTransactionId, WebCore::PointerID pointerId)
1129 {
1130     auto invalidTargetForSingleClick = !m_potentialTapNode;
1131     if (!invalidTargetForSingleClick) {
1132         bool targetRenders = m_potentialTapNode->renderer();
1133         if (!targetRenders && is<Element>(m_potentialTapNode.get()))
1134             targetRenders = downcast<Element>(*m_potentialTapNode).renderOrDisplayContentsStyle();
1135         invalidTargetForSingleClick = !targetRenders && !is<HTMLAreaElement>(m_potentialTapNode.get());
1136     }
1137     if (invalidTargetForSingleClick) {
1138         commitPotentialTapFailed();
1139         return;
1140     }
1141
1142     FloatPoint adjustedPoint;
1143     Node* nodeRespondingToClick = m_page->mainFrame().nodeRespondingToClickEvents(m_potentialTapLocation, adjustedPoint, m_potentialTapSecurityOrigin.get());
1144     Frame* frameRespondingToClick = nodeRespondingToClick ? nodeRespondingToClick->document().frame() : nullptr;
1145
1146     if (!frameRespondingToClick || lastLayerTreeTransactionId < WebFrame::fromCoreFrame(*frameRespondingToClick)->firstLayerTreeTransactionIDAfterDidCommitLoad()) {
1147         commitPotentialTapFailed();
1148         return;
1149     }
1150
1151     if (m_potentialTapNode == nodeRespondingToClick) {
1152 #if ENABLE(DATA_DETECTION)
1153         if (is<Element>(*nodeRespondingToClick) && DataDetection::shouldCancelDefaultAction(downcast<Element>(*nodeRespondingToClick))) {
1154             InteractionInformationRequest request(roundedIntPoint(m_potentialTapLocation));
1155             requestPositionInformation(request);
1156             commitPotentialTapFailed();
1157         } else
1158 #endif
1159             handleSyntheticClick(*nodeRespondingToClick, adjustedPoint, modifiers, pointerId);
1160     } else
1161         commitPotentialTapFailed();
1162
1163     m_potentialTapNode = nullptr;
1164     m_potentialTapLocation = FloatPoint();
1165     m_potentialTapSecurityOrigin = nullptr;
1166 }
1167
1168 void WebPage::commitPotentialTapFailed()
1169 {
1170     ContentChangeObserver::didCancelPotentialTap(m_page->mainFrame());
1171     if (!m_page->focusController().focusedOrMainFrame().selection().selection().isContentEditable())
1172         clearSelection();
1173
1174     send(Messages::WebPageProxy::CommitPotentialTapFailed());
1175     send(Messages::WebPageProxy::DidNotHandleTapAsClick(roundedIntPoint(m_potentialTapLocation)));
1176 }
1177
1178 void WebPage::cancelPotentialTap()
1179 {
1180     ContentChangeObserver::didCancelPotentialTap(m_page->mainFrame());
1181     cancelPotentialTapInFrame(m_mainFrame);
1182 }
1183
1184 void WebPage::cancelPotentialTapInFrame(WebFrame& frame)
1185 {
1186     if (m_potentialTapNode) {
1187         auto* potentialTapFrame = m_potentialTapNode->document().frame();
1188         if (potentialTapFrame && !potentialTapFrame->tree().isDescendantOf(frame.coreFrame()))
1189             return;
1190     }
1191
1192     m_potentialTapNode = nullptr;
1193     m_potentialTapLocation = FloatPoint();
1194     m_potentialTapSecurityOrigin = nullptr;
1195 }
1196
1197 void WebPage::didRecognizeLongPress()
1198 {
1199     ContentChangeObserver::didRecognizeLongPress(m_page->mainFrame());
1200 }
1201
1202 void WebPage::tapHighlightAtPosition(uint64_t requestID, const FloatPoint& position)
1203 {
1204     Frame& mainframe = m_page->mainFrame();
1205     FloatPoint adjustedPoint;
1206     sendTapHighlightForNodeIfNecessary(requestID, mainframe.nodeRespondingToClickEvents(position, adjustedPoint));
1207 }
1208
1209 void WebPage::inspectorNodeSearchMovedToPosition(const FloatPoint& position)
1210 {
1211     IntPoint adjustedPoint = roundedIntPoint(position);
1212     Frame& mainframe = m_page->mainFrame();
1213
1214     mainframe.eventHandler().mouseMoved(PlatformMouseEvent(adjustedPoint, adjustedPoint, NoButton, PlatformEvent::MouseMoved, 0, false, false, false, false, { }, 0, WebCore::NoTap));
1215     mainframe.document()->updateStyleIfNeeded();
1216 }
1217
1218 void WebPage::inspectorNodeSearchEndedAtPosition(const FloatPoint& position)
1219 {
1220     if (Node* node = m_page->mainFrame().deepestNodeAtLocation(position))
1221         node->inspect();
1222 }
1223
1224 void WebPage::updateInputContextAfterBlurringAndRefocusingElementIfNeeded(Element& element)
1225 {
1226     if (m_recentlyBlurredElement != &element || !m_isShowingInputViewForFocusedElement)
1227         return;
1228
1229     m_hasPendingInputContextUpdateAfterBlurringAndRefocusingElement = true;
1230     callOnMainThread([this, protectedThis = makeRefPtr(this)] {
1231         if (m_hasPendingInputContextUpdateAfterBlurringAndRefocusingElement)
1232             send(Messages::WebPageProxy::UpdateInputContextAfterBlurringAndRefocusingElement());
1233         m_hasPendingInputContextUpdateAfterBlurringAndRefocusingElement = false;
1234     });
1235 }
1236
1237 void WebPage::blurFocusedElement()
1238 {
1239     if (!m_focusedElement)
1240         return;
1241
1242     m_focusedElement->blur();
1243 }
1244
1245 void WebPage::setIsShowingInputViewForFocusedElement(bool showingInputView)
1246 {
1247     m_isShowingInputViewForFocusedElement = showingInputView;
1248 }
1249
1250 void WebPage::setFocusedElementValue(const String& value)
1251 {
1252     // FIXME: should also handle the case of HTMLSelectElement.
1253     if (is<HTMLInputElement>(m_focusedElement.get()))
1254         downcast<HTMLInputElement>(*m_focusedElement).setValue(value, DispatchInputAndChangeEvent);
1255 }
1256
1257 void WebPage::setFocusedElementValueAsNumber(double value)
1258 {
1259     if (is<HTMLInputElement>(m_focusedElement.get()))
1260         downcast<HTMLInputElement>(*m_focusedElement).setValueAsNumber(value, DispatchInputAndChangeEvent);
1261 }
1262
1263 void WebPage::setFocusedElementSelectedIndex(uint32_t index, bool allowMultipleSelection)
1264 {
1265     if (is<HTMLSelectElement>(m_focusedElement.get()))
1266         downcast<HTMLSelectElement>(*m_focusedElement).optionSelectedByUser(index, true, allowMultipleSelection);
1267 }
1268
1269 void WebPage::showInspectorHighlight(const WebCore::Highlight& highlight)
1270 {
1271     send(Messages::WebPageProxy::ShowInspectorHighlight(highlight));
1272 }
1273
1274 void WebPage::hideInspectorHighlight()
1275 {
1276     send(Messages::WebPageProxy::HideInspectorHighlight());
1277 }
1278
1279 void WebPage::showInspectorIndication()
1280 {
1281     send(Messages::WebPageProxy::ShowInspectorIndication());
1282 }
1283
1284 void WebPage::hideInspectorIndication()
1285 {
1286     send(Messages::WebPageProxy::HideInspectorIndication());
1287 }
1288
1289 void WebPage::enableInspectorNodeSearch()
1290 {
1291     send(Messages::WebPageProxy::EnableInspectorNodeSearch());
1292 }
1293
1294 void WebPage::disableInspectorNodeSearch()
1295 {
1296     send(Messages::WebPageProxy::DisableInspectorNodeSearch());
1297 }
1298
1299 void WebPage::setForceAlwaysUserScalable(bool userScalable)
1300 {
1301     m_forceAlwaysUserScalable = userScalable;
1302     m_viewportConfiguration.setForceAlwaysUserScalable(userScalable);
1303 }
1304
1305 static IntRect elementBoundsInFrame(const Frame& frame, const Element& focusedElement)
1306 {
1307     frame.document()->updateLayoutIgnorePendingStylesheets();
1308     
1309     if (focusedElement.hasTagName(HTMLNames::textareaTag) || focusedElement.hasTagName(HTMLNames::inputTag) || focusedElement.hasTagName(HTMLNames::selectTag))
1310         return WebPage::absoluteInteractionBoundsForElement(focusedElement);
1311
1312     if (auto* rootEditableElement = focusedElement.rootEditableElement())
1313         return WebPage::absoluteInteractionBoundsForElement(*rootEditableElement);
1314
1315     return { };
1316 }
1317
1318 static IntPoint constrainPoint(const IntPoint& point, const Frame& frame, const Element& focusedElement)
1319 {
1320     ASSERT(&focusedElement.document() == frame.document());
1321     const int DEFAULT_CONSTRAIN_INSET = 2;
1322     IntRect innerFrame = elementBoundsInFrame(frame, focusedElement);
1323     IntPoint constrainedPoint = point;
1324
1325     int minX = innerFrame.x() + DEFAULT_CONSTRAIN_INSET;
1326     int maxX = innerFrame.maxX() - DEFAULT_CONSTRAIN_INSET;
1327     int minY = innerFrame.y() + DEFAULT_CONSTRAIN_INSET;
1328     int maxY = innerFrame.maxY() - DEFAULT_CONSTRAIN_INSET;
1329
1330     if (point.x() < minX)
1331         constrainedPoint.setX(minX);
1332     else if (point.x() > maxX)
1333         constrainedPoint.setX(maxX);
1334
1335     if (point.y() < minY)
1336         constrainedPoint.setY(minY);
1337     else if (point.y() >= maxY)
1338         constrainedPoint.setY(maxY);
1339                     
1340     return constrainedPoint;
1341 }
1342
1343 void WebPage::selectWithGesture(const IntPoint& point, uint32_t granularity, uint32_t gestureType, uint32_t gestureState, bool isInteractingWithFocusedElement, CallbackID callbackID)
1344 {
1345     if (static_cast<GestureRecognizerState>(gestureState) == GestureRecognizerState::Began)
1346         setFocusedFrameBeforeSelectingTextAtLocation(point);
1347
1348     auto& frame = m_page->focusController().focusedOrMainFrame();
1349     VisiblePosition position = visiblePositionInFocusedNodeForPoint(frame, point, isInteractingWithFocusedElement);
1350
1351     if (position.isNull()) {
1352         send(Messages::WebPageProxy::GestureCallback(point, gestureType, gestureState, 0, callbackID));
1353         return;
1354     }
1355     RefPtr<Range> range;
1356     SelectionFlags flags = None;
1357     GestureRecognizerState wkGestureState = static_cast<GestureRecognizerState>(gestureState);
1358     switch (static_cast<GestureType>(gestureType)) {
1359     case GestureType::PhraseBoundary:
1360     {
1361         if (!frame.editor().hasComposition())
1362             break;
1363         RefPtr<Range> markedRange = frame.editor().compositionRange();
1364         if (position < markedRange->startPosition())
1365             position = markedRange->startPosition();
1366         if (position > markedRange->endPosition())
1367             position = markedRange->endPosition();
1368         if (wkGestureState != GestureRecognizerState::Began)
1369             flags = distanceBetweenPositions(markedRange->startPosition(), frame.selection().selection().start()) != distanceBetweenPositions(markedRange->startPosition(), position) ? PhraseBoundaryChanged : None;
1370         else
1371             flags = PhraseBoundaryChanged;
1372         range = Range::create(*frame.document(), position, position);
1373     }
1374         break;
1375
1376     case GestureType::OneFingerTap:
1377     {
1378         VisiblePosition result;
1379         // move the position at the end of the word
1380         if (atBoundaryOfGranularity(position, LineGranularity, DirectionForward)) {
1381             // Don't cross line boundaries.
1382             result = position;
1383         } else if (withinTextUnitOfGranularity(position, WordGranularity, DirectionForward)) {
1384             // The position lies within a word.
1385             RefPtr<Range> wordRange = enclosingTextUnitOfGranularity(position, WordGranularity, DirectionForward);
1386             if (wordRange) {
1387                 result = wordRange->startPosition();
1388                 if (distanceBetweenPositions(position, result) > 1)
1389                     result = wordRange->endPosition();
1390             }
1391             flags = WordIsNearTap;
1392         } else if (atBoundaryOfGranularity(position, WordGranularity, DirectionBackward)) {
1393             // The position is at the end of a word.
1394             result = position;
1395         } else {
1396             // The position is not within a word.
1397             // Go to the next boundary.
1398             result = positionOfNextBoundaryOfGranularity(position, WordGranularity, DirectionForward);
1399
1400             // If there is no such boundary we go to the end of the element.
1401             if (result.isNull())
1402                 result = endOfEditableContent(position);
1403         }
1404         if (result.isNotNull())
1405             range = Range::create(*frame.document(), result, result);
1406     }
1407         break;
1408
1409     case GestureType::Loupe:
1410         if (position.rootEditableElement())
1411             range = Range::create(*frame.document(), position, position);
1412         else
1413 #if !PLATFORM(MACCATALYST)
1414             range = wordRangeFromPosition(position);
1415 #else
1416             switch (wkGestureState) {
1417             case GestureRecognizerState::Began:
1418                 m_startingGestureRange = Range::create(*frame.document(), position, position);
1419                 break;
1420             case GestureRecognizerState::Changed:
1421                 if (m_startingGestureRange) {
1422                     if (m_startingGestureRange->startPosition() < position)
1423                         range = Range::create(*frame.document(), m_startingGestureRange->startPosition(), position);
1424                     else
1425                         range = Range::create(*frame.document(), position, m_startingGestureRange->startPosition());
1426                 }
1427                 break;
1428             case GestureRecognizerState::Ended:
1429             case GestureRecognizerState::Cancelled:
1430                 m_startingGestureRange = nullptr;
1431                 break;
1432             case GestureRecognizerState::Failed:
1433             case GestureRecognizerState::Possible:
1434                 ASSERT_NOT_REACHED();
1435                 break;
1436             }
1437 #endif
1438         break;
1439
1440     case GestureType::TapAndAHalf:
1441         switch (wkGestureState) {
1442         case GestureRecognizerState::Began:
1443             range = wordRangeFromPosition(position);
1444             m_currentWordRange = range ? RefPtr<Range>(Range::create(*frame.document(), range->startPosition(), range->endPosition())) : nullptr;
1445             break;
1446         case GestureRecognizerState::Changed:
1447             if (!m_currentWordRange)
1448                 break;
1449             range = Range::create(*frame.document(), m_currentWordRange->startPosition(), m_currentWordRange->endPosition());
1450             if (position < range->startPosition())
1451                 range->setStart(position.deepEquivalent());
1452             if (position > range->endPosition())
1453                 range->setEnd(position.deepEquivalent());
1454             break;
1455         case GestureRecognizerState::Ended:
1456         case GestureRecognizerState::Cancelled:
1457             m_currentWordRange = nullptr;
1458             break;
1459         case GestureRecognizerState::Failed:
1460         case GestureRecognizerState::Possible:
1461             ASSERT_NOT_REACHED();
1462         }
1463         break;
1464
1465     case GestureType::OneFingerDoubleTap:
1466         if (atBoundaryOfGranularity(position, LineGranularity, DirectionForward)) {
1467             // Double-tap at end of line only places insertion point there.
1468             // This helps to get the callout for pasting at ends of lines,
1469             // paragraphs, and documents.
1470             range = Range::create(*frame.document(), position, position);
1471          } else
1472             range = wordRangeFromPosition(position);
1473         break;
1474
1475     case GestureType::TwoFingerSingleTap:
1476         // Single tap with two fingers selects the entire paragraph.
1477         range = enclosingTextUnitOfGranularity(position, ParagraphGranularity, DirectionForward);
1478         break;
1479
1480     case GestureType::OneFingerTripleTap:
1481         if (atBoundaryOfGranularity(position, LineGranularity, DirectionForward)) {
1482             // Triple-tap at end of line only places insertion point there.
1483             // This helps to get the callout for pasting at ends of lines,
1484             // paragraphs, and documents.
1485             range = Range::create(*frame.document(), position, position);
1486         } else
1487             range = enclosingTextUnitOfGranularity(position, ParagraphGranularity, DirectionForward);
1488         break;
1489
1490     default:
1491         break;
1492     }
1493     if (range)
1494         frame.selection().setSelectedRange(range.get(), position.affinity(), WebCore::FrameSelection::ShouldCloseTyping::Yes, UserTriggered);
1495
1496     send(Messages::WebPageProxy::GestureCallback(point, gestureType, gestureState, static_cast<uint32_t>(flags), callbackID));
1497 }
1498
1499 static RefPtr<Range> rangeForPointInRootViewCoordinates(Frame& frame, const IntPoint& pointInRootViewCoordinates, bool baseIsStart)
1500 {
1501     VisibleSelection existingSelection = frame.selection().selection();
1502     VisiblePosition selectionStart = existingSelection.visibleStart();
1503     VisiblePosition selectionEnd = existingSelection.visibleEnd();
1504
1505     auto pointInDocument = frame.view()->rootViewToContents(pointInRootViewCoordinates);
1506
1507     if (baseIsStart) {
1508         int startY = selectionStart.absoluteCaretBounds().center().y();
1509         if (pointInDocument.y() < startY)
1510             pointInDocument.setY(startY);
1511     } else {
1512         int endY = selectionEnd.absoluteCaretBounds().center().y();
1513         if (pointInDocument.y() > endY)
1514             pointInDocument.setY(endY);
1515     }
1516     
1517     VisiblePosition result;
1518     RefPtr<Range> range;
1519
1520     constexpr OptionSet<HitTestRequest::RequestType> hitType { HitTestRequest::ReadOnly, HitTestRequest::Active, HitTestRequest::AllowVisibleChildFrameContentOnly };
1521     HitTestResult hitTest = frame.eventHandler().hitTestResultAtPoint(pointInDocument, hitType);
1522     if (hitTest.targetNode())
1523         result = frame.eventHandler().selectionExtentRespectingEditingBoundary(frame.selection().selection(), hitTest.localPoint(), hitTest.targetNode()).deepEquivalent();
1524     else
1525         result = frame.visiblePositionForPoint(pointInDocument).deepEquivalent();
1526     
1527     if (baseIsStart) {
1528         if (comparePositions(result, selectionStart) <= 0)
1529             result = selectionStart.next();
1530         else if (&selectionStart.deepEquivalent().anchorNode()->treeScope() != &hitTest.targetNode()->treeScope())
1531             result = VisibleSelection::adjustPositionForEnd(result.deepEquivalent(), selectionStart.deepEquivalent().containerNode());
1532         
1533         if (result.isNotNull())
1534             range = Range::create(*frame.document(), selectionStart, result);
1535     } else {
1536         if (comparePositions(selectionEnd, result) <= 0)
1537             result = selectionEnd.previous();
1538         else if (&hitTest.targetNode()->treeScope() != &selectionEnd.deepEquivalent().anchorNode()->treeScope())
1539             result = VisibleSelection::adjustPositionForStart(result.deepEquivalent(), selectionEnd.deepEquivalent().containerNode());
1540         
1541         if (result.isNotNull())
1542             range = Range::create(*frame.document(), result.deepEquivalent(), selectionEnd);
1543     }
1544     
1545     return range;
1546 }
1547
1548 static RefPtr<Range> rangeAtWordBoundaryForPosition(Frame* frame, const VisiblePosition& position, bool baseIsStart, SelectionDirection direction)
1549 {
1550     SelectionDirection sameDirection = baseIsStart ? DirectionForward : DirectionBackward;
1551     SelectionDirection oppositeDirection = baseIsStart ? DirectionBackward : DirectionForward;
1552     VisiblePosition base = baseIsStart ? frame->selection().selection().visibleStart() : frame->selection().selection().visibleEnd();
1553     VisiblePosition extent = baseIsStart ? frame->selection().selection().visibleEnd() : frame->selection().selection().visibleStart();
1554     VisiblePosition initialExtent = position;
1555
1556     if (atBoundaryOfGranularity(extent, WordGranularity, sameDirection)) {
1557         // This is a word boundary. Leave selection where it is.
1558         return nullptr;
1559     }
1560
1561     if (atBoundaryOfGranularity(extent, WordGranularity, oppositeDirection)) {
1562         // This is a word boundary in the wrong direction. Nudge the selection to a character before proceeding.
1563         extent = baseIsStart ? extent.previous() : extent.next();
1564     }
1565
1566     // Extend to the boundary of the word.
1567
1568     VisiblePosition wordBoundary = positionOfNextBoundaryOfGranularity(extent, WordGranularity, sameDirection);
1569     if (wordBoundary.isNotNull()
1570         && atBoundaryOfGranularity(wordBoundary, WordGranularity, sameDirection)
1571         && initialExtent != wordBoundary) {
1572         extent = wordBoundary;
1573         return (base < extent) ? Range::create(*frame->document(), base, extent) : Range::create(*frame->document(), extent, base);
1574     }
1575     // Conversely, if the initial extent equals the current word boundary, then
1576     // run the rest of this function to see if the selection should extend
1577     // the other direction to the other word.
1578
1579     // If this is where the extent was initially, then iterate in the other direction in the document until we hit the next word.
1580     while (extent.isNotNull()
1581         && !atBoundaryOfGranularity(extent, WordGranularity, sameDirection)
1582         && extent != base
1583         && !atBoundaryOfGranularity(extent, LineGranularity, sameDirection)
1584         && !atBoundaryOfGranularity(extent, LineGranularity, oppositeDirection)) {
1585         extent = baseIsStart ? extent.next() : extent.previous();
1586     }
1587
1588     // Don't let the smart extension make the extent equal the base.
1589     // Expand out to word boundary.
1590     if (extent.isNull() || extent == base)
1591         extent = wordBoundary;
1592     if (extent.isNull())
1593         return nullptr;
1594
1595     return (base < extent) ? Range::create(*frame->document(), base, extent) : Range::create(*frame->document(), extent, base);
1596 }
1597
1598 IntRect WebPage::rootViewBoundsForElement(const Element& element)
1599 {
1600     auto* frame = element.document().frame();
1601     if (!frame)
1602         return { };
1603
1604     auto* view = frame->view();
1605     if (!view)
1606         return { };
1607
1608     auto* renderer = element.renderer();
1609     if (!renderer)
1610         return { };
1611
1612     return view->contentsToRootView(renderer->absoluteBoundingBoxRect());
1613 }
1614
1615 IntRect WebPage::absoluteInteractionBoundsForElement(const Element& element)
1616 {
1617     auto* frame = element.document().frame();
1618     if (!frame)
1619         return { };
1620
1621     auto* view = frame->view();
1622     if (!view)
1623         return { };
1624
1625     auto* renderer = element.renderer();
1626     if (!renderer)
1627         return { };
1628
1629     if (is<RenderBox>(*renderer)) {
1630         auto& box = downcast<RenderBox>(*renderer);
1631
1632         FloatRect rect;
1633         // FIXME: want borders or not?
1634         if (box.style().isOverflowVisible())
1635             rect = box.layoutOverflowRect();
1636         else
1637             rect = box.clientBoxRect();
1638         return box.localToAbsoluteQuad(rect).enclosingBoundingBox();
1639     }
1640
1641     auto& style = renderer->style();
1642     FloatRect boundingBox = renderer->absoluteBoundingBoxRect(true /* use transforms*/);
1643     // This is wrong. It's subtracting borders after converting to absolute coords on something that probably doesn't represent a rectangular element.
1644     boundingBox.move(style.borderLeftWidth(), style.borderTopWidth());
1645     boundingBox.setWidth(boundingBox.width() - style.borderLeftWidth() - style.borderRightWidth());
1646     boundingBox.setHeight(boundingBox.height() - style.borderBottomWidth() - style.borderTopWidth());
1647     return enclosingIntRect(boundingBox);
1648 }
1649
1650 IntRect WebPage::rootViewInteractionBoundsForElement(const Element& element)
1651 {
1652     auto* frame = element.document().frame();
1653     if (!frame)
1654         return { };
1655
1656     auto* view = frame->view();
1657     if (!view)
1658         return { };
1659
1660     return view->contentsToRootView(absoluteInteractionBoundsForElement(element));
1661 }
1662
1663 void WebPage::clearSelection()
1664 {
1665     m_startingGestureRange = nullptr;
1666     m_page->focusController().focusedOrMainFrame().selection().clear();
1667 }
1668
1669 void WebPage::dispatchSyntheticMouseEventsForSelectionGesture(SelectionTouch touch, const IntPoint& point)
1670 {
1671     auto frame = makeRef(m_page->focusController().focusedOrMainFrame());
1672     if (!frame->selection().selection().isContentEditable())
1673         return;
1674
1675     IntRect focusedElementRect;
1676     if (m_focusedElement)
1677         focusedElementRect = rootViewInteractionBoundsForElement(*m_focusedElement);
1678
1679     if (focusedElementRect.isEmpty())
1680         return;
1681
1682     auto adjustedPoint = point.constrainedBetween(focusedElementRect.minXMinYCorner(), focusedElementRect.maxXMaxYCorner());
1683     auto& eventHandler = m_page->mainFrame().eventHandler();
1684     switch (touch) {
1685     case SelectionTouch::Started:
1686         eventHandler.handleMousePressEvent({ adjustedPoint, adjustedPoint, LeftButton, PlatformEvent::MousePressed, 1, false, false, false, false, WallTime::now(), WebCore::ForceAtClick, NoTap });
1687         break;
1688     case SelectionTouch::Moved:
1689         eventHandler.dispatchSyntheticMouseMove({ adjustedPoint, adjustedPoint, LeftButton, PlatformEvent::MouseMoved, 0, false, false, false, false, WallTime::now(), WebCore::ForceAtClick, NoTap });
1690         break;
1691     case SelectionTouch::Ended:
1692     case SelectionTouch::EndedMovingForward:
1693     case SelectionTouch::EndedMovingBackward:
1694     case SelectionTouch::EndedNotMoving:
1695         eventHandler.handleMouseReleaseEvent({ adjustedPoint, adjustedPoint, LeftButton, PlatformEvent::MouseReleased, 1, false, false, false, false, WallTime::now(), WebCore::ForceAtClick, NoTap });
1696         break;
1697     }
1698 }
1699
1700 void WebPage::updateSelectionWithTouches(const IntPoint& point, uint32_t touches, bool baseIsStart, CallbackID callbackID)
1701 {
1702     Frame& frame = m_page->focusController().focusedOrMainFrame();
1703     IntPoint pointInDocument = frame.view()->rootViewToContents(point);
1704     VisiblePosition position = frame.visiblePositionForPoint(pointInDocument);
1705     if (position.isNull()) {
1706         send(Messages::WebPageProxy::TouchesCallback(point, touches, 0, callbackID));
1707         return;
1708     }
1709
1710     RefPtr<Range> range;
1711     VisiblePosition result;
1712     SelectionFlags flags = None;
1713
1714     auto selectionTouch = static_cast<SelectionTouch>(touches);
1715     if (shouldDispatchSyntheticMouseEventsWhenModifyingSelection())
1716         dispatchSyntheticMouseEventsForSelectionGesture(selectionTouch, point);
1717
1718     switch (selectionTouch) {
1719     case SelectionTouch::Started:
1720     case SelectionTouch::EndedNotMoving:
1721         break;
1722     
1723     case SelectionTouch::Ended:
1724         if (frame.selection().selection().isContentEditable()) {
1725             result = closestWordBoundaryForPosition(position);
1726             if (result.isNotNull())
1727                 range = Range::create(*frame.document(), result, result);
1728         } else
1729             range = rangeForPointInRootViewCoordinates(frame, point, baseIsStart);
1730         break;
1731
1732     case SelectionTouch::EndedMovingForward:
1733         range = rangeAtWordBoundaryForPosition(&frame, position, baseIsStart, DirectionForward);
1734         break;
1735         
1736     case SelectionTouch::EndedMovingBackward:
1737         range = rangeAtWordBoundaryForPosition(&frame, position, baseIsStart, DirectionBackward);
1738         break;
1739
1740     case SelectionTouch::Moved:
1741         range = rangeForPointInRootViewCoordinates(frame, point, baseIsStart);
1742         break;
1743     }
1744     if (range)
1745         frame.selection().setSelectedRange(range.get(), position.affinity(), WebCore::FrameSelection::ShouldCloseTyping::Yes, UserTriggered);
1746
1747     send(Messages::WebPageProxy::TouchesCallback(point, touches, flags, callbackID));
1748 }
1749
1750 void WebPage::selectWithTwoTouches(const WebCore::IntPoint& from, const WebCore::IntPoint& to, uint32_t gestureType, uint32_t gestureState, CallbackID callbackID)
1751 {
1752     Frame& frame = m_page->focusController().focusedOrMainFrame();
1753     VisiblePosition fromPosition = frame.visiblePositionForPoint(frame.view()->rootViewToContents(from));
1754     VisiblePosition toPosition = frame.visiblePositionForPoint(frame.view()->rootViewToContents(to));
1755     RefPtr<Range> range;
1756     if (fromPosition.isNotNull() && toPosition.isNotNull()) {
1757         if (fromPosition < toPosition)
1758             range = Range::create(*frame.document(), fromPosition, toPosition);
1759         else
1760             range = Range::create(*frame.document(), toPosition, fromPosition);
1761         frame.selection().setSelectedRange(range.get(), fromPosition.affinity(), WebCore::FrameSelection::ShouldCloseTyping::Yes, UserTriggered);
1762     }
1763
1764     // We can use the same callback for the gestures with one point.
1765     send(Messages::WebPageProxy::GestureCallback(from, gestureType, gestureState, 0, callbackID));
1766 }
1767
1768 void WebPage::extendSelection(uint32_t granularity)
1769 {
1770     Frame& frame = m_page->focusController().focusedOrMainFrame();
1771     // For the moment we handle only WordGranularity.
1772     if (granularity != WordGranularity || !frame.selection().isCaret())
1773         return;
1774
1775     VisiblePosition position = frame.selection().selection().start();
1776     auto wordRange = wordRangeFromPosition(position);
1777     if (!wordRange)
1778         return;
1779
1780     IntPoint endLocationForSyntheticMouseEvents;
1781     bool shouldDispatchMouseEvents = shouldDispatchSyntheticMouseEventsWhenModifyingSelection();
1782     if (shouldDispatchMouseEvents) {
1783         auto startLocationForSyntheticMouseEvents = frame.view()->contentsToRootView(VisiblePosition(wordRange->startPosition()).absoluteCaretBounds()).center();
1784         endLocationForSyntheticMouseEvents = frame.view()->contentsToRootView(VisiblePosition(wordRange->endPosition()).absoluteCaretBounds()).center();
1785         dispatchSyntheticMouseEventsForSelectionGesture(SelectionTouch::Started, startLocationForSyntheticMouseEvents);
1786         dispatchSyntheticMouseEventsForSelectionGesture(SelectionTouch::Moved, endLocationForSyntheticMouseEvents);
1787     }
1788
1789     frame.selection().setSelectedRange(wordRange.get(), position.affinity(), WebCore::FrameSelection::ShouldCloseTyping::Yes, UserTriggered);
1790
1791     if (shouldDispatchMouseEvents)
1792         dispatchSyntheticMouseEventsForSelectionGesture(SelectionTouch::Ended, endLocationForSyntheticMouseEvents);
1793 }
1794
1795 void WebPage::platformDidSelectAll()
1796 {
1797     if (!shouldDispatchSyntheticMouseEventsWhenModifyingSelection())
1798         return;
1799
1800     auto frame = makeRef(m_page->focusController().focusedOrMainFrame());
1801     auto startCaretRect = frame->view()->contentsToRootView(VisiblePosition(frame->selection().selection().start()).absoluteCaretBounds());
1802     auto endCaretRect = frame->view()->contentsToRootView(VisiblePosition(frame->selection().selection().end()).absoluteCaretBounds());
1803     dispatchSyntheticMouseEventsForSelectionGesture(SelectionTouch::Started, startCaretRect.center());
1804     dispatchSyntheticMouseEventsForSelectionGesture(SelectionTouch::Moved, endCaretRect.center());
1805     dispatchSyntheticMouseEventsForSelectionGesture(SelectionTouch::Ended, endCaretRect.center());
1806 }
1807
1808 void WebPage::selectWordBackward()
1809 {
1810     Frame& frame = m_page->focusController().focusedOrMainFrame();
1811     if (!frame.selection().isCaret())
1812         return;
1813
1814     VisiblePosition position = frame.selection().selection().start();
1815     VisiblePosition startPosition = positionOfNextBoundaryOfGranularity(position, WordGranularity, DirectionBackward);
1816     if (startPosition.isNotNull() && startPosition != position)
1817         frame.selection().setSelectedRange(Range::create(*frame.document(), startPosition, position).ptr(), position.affinity(), WebCore::FrameSelection::ShouldCloseTyping::Yes, UserTriggered);
1818 }
1819
1820 void WebPage::moveSelectionByOffset(int32_t offset, CallbackID callbackID)
1821 {
1822     Frame& frame = m_page->focusController().focusedOrMainFrame();
1823     
1824     VisiblePosition startPosition = frame.selection().selection().end();
1825     if (startPosition.isNull())
1826         return;
1827     SelectionDirection direction = offset < 0 ? DirectionBackward : DirectionForward;
1828     VisiblePosition position = startPosition;
1829     for (int i = 0; i < abs(offset); ++i) {
1830         position = positionOfNextBoundaryOfGranularity(position, CharacterGranularity, direction);
1831         if (position.isNull())
1832             break;
1833     }
1834     if (position.isNotNull() && startPosition != position)
1835         frame.selection().setSelectedRange(Range::create(*frame.document(), position, position).ptr(), position.affinity(), WebCore::FrameSelection::ShouldCloseTyping::Yes, UserTriggered);
1836     send(Messages::WebPageProxy::VoidCallback(callbackID));
1837 }
1838     
1839 void WebPage::startAutoscrollAtPosition(const WebCore::FloatPoint& positionInWindow)
1840 {
1841     if (m_focusedElement && m_focusedElement->renderer()) {
1842         m_page->mainFrame().eventHandler().startSelectionAutoscroll(m_focusedElement->renderer(), positionInWindow);
1843         return;
1844     }
1845     
1846     Frame& frame = m_page->focusController().focusedOrMainFrame();
1847     VisibleSelection selection = frame.selection().selection();
1848     if (!selection.isRange())
1849         return;
1850     RefPtr<Range> range = frame.selection().toNormalizedRange();
1851     if (!range)
1852         return;
1853     auto* renderer = range->startContainer().renderer();
1854     if (!renderer)
1855         return;
1856
1857     m_page->mainFrame().eventHandler().startSelectionAutoscroll(renderer, positionInWindow);
1858 }
1859     
1860 void WebPage::cancelAutoscroll()
1861 {
1862     m_page->mainFrame().eventHandler().cancelSelectionAutoscroll();
1863 }
1864
1865 void WebPage::requestEvasionRectsAboveSelection(CompletionHandler<void(const Vector<FloatRect>&)>&& reply)
1866 {
1867     auto& frame = m_page->focusController().focusedOrMainFrame();
1868     auto frameView = makeRefPtr(frame.view());
1869     if (!frameView) {
1870         reply({ });
1871         return;
1872     }
1873
1874     auto& selection = frame.selection().selection();
1875     if (selection.isNone()) {
1876         reply({ });
1877         return;
1878     }
1879
1880     auto selectedRange = selection.toNormalizedRange();
1881     if (!selectedRange) {
1882         reply({ });
1883         return;
1884     }
1885
1886     if (!m_focusedElement || !m_focusedElement->renderer() || isTransparentOrFullyClipped(*m_focusedElement)) {
1887         reply({ });
1888         return;
1889     }
1890
1891     float scaleFactor = pageScaleFactor();
1892     const double factorOfContentArea = 0.5;
1893     auto unobscuredContentArea = m_page->mainFrame().view()->unobscuredContentRect().area();
1894     if (unobscuredContentArea.hasOverflowed()) {
1895         reply({ });
1896         return;
1897     }
1898
1899     double contextMenuAreaLimit = factorOfContentArea * scaleFactor * unobscuredContentArea.unsafeGet();
1900
1901     FloatRect selectionBoundsInRootViewCoordinates;
1902     if (selection.isRange())
1903         selectionBoundsInRootViewCoordinates = frameView->contentsToRootView(selectedRange->absoluteBoundingBox());
1904     else
1905         selectionBoundsInRootViewCoordinates = frameView->contentsToRootView(frame.selection().absoluteCaretBounds());
1906
1907     auto centerOfTargetBounds = selectionBoundsInRootViewCoordinates.center();
1908     FloatPoint centerTopInRootViewCoordinates { centerOfTargetBounds.x(), selectionBoundsInRootViewCoordinates.y() };
1909
1910     auto clickableNonEditableNode = [&] (const FloatPoint& locationInRootViewCoordinates) -> Node* {
1911         FloatPoint adjustedPoint;
1912         auto* hitNode = m_page->mainFrame().nodeRespondingToClickEvents(locationInRootViewCoordinates, adjustedPoint);
1913         if (!hitNode || is<HTMLBodyElement>(hitNode) || is<Document>(hitNode) || hitNode->hasEditableStyle())
1914             return nullptr;
1915
1916         return hitNode;
1917     };
1918
1919     // This heuristic attempts to find a list of rects to avoid when showing the callout menu on iOS.
1920     // First, hit-test several points above the bounds of the selection rect in search of clickable nodes that are not editable.
1921     // Secondly, hit-test several points around the edges of the selection rect and exclude any nodes found in the first round of
1922     // hit-testing if these nodes are also reachable by moving outwards from the left, right, or bottom edges of the selection.
1923     // Additionally, exclude any hit-tested nodes that are either very large relative to the size of the root view, or completely
1924     // encompass the selection bounds. The resulting rects are the bounds of these hit-tested nodes in root view coordinates.
1925     HashSet<Ref<Node>> hitTestedNodes;
1926     Vector<FloatRect> rectsToAvoidInRootViewCoordinates;
1927     const Vector<FloatPoint, 5> offsetsForHitTesting {{ -30, -50 }, { 30, -50 }, { -60, -35 }, { 60, -35 }, { 0, -20 }};
1928     for (auto offset : offsetsForHitTesting) {
1929         offset.scale(1 / scaleFactor);
1930         if (auto* hitNode = clickableNonEditableNode(centerTopInRootViewCoordinates + offset))
1931             hitTestedNodes.add(*hitNode);
1932     }
1933
1934     const float marginForHitTestingSurroundingNodes = 80 / scaleFactor;
1935     Vector<FloatPoint, 3> exclusionHitTestLocations {
1936         { selectionBoundsInRootViewCoordinates.x() - marginForHitTestingSurroundingNodes, centerOfTargetBounds.y() },
1937         { centerOfTargetBounds.x(), selectionBoundsInRootViewCoordinates.maxY() + marginForHitTestingSurroundingNodes },
1938         { selectionBoundsInRootViewCoordinates.maxX() + marginForHitTestingSurroundingNodes, centerOfTargetBounds.y() }
1939     };
1940
1941     for (auto& location : exclusionHitTestLocations) {
1942         if (auto* nodeToExclude = clickableNonEditableNode(location))
1943             hitTestedNodes.remove(*nodeToExclude);
1944     }
1945
1946     for (auto& node : hitTestedNodes) {
1947         auto frameView = makeRefPtr(node->document().view());
1948         auto* renderer = node->renderer();
1949         if (!renderer || !frameView)
1950             continue;
1951
1952         auto bounds = frameView->contentsToRootView(renderer->absoluteBoundingBoxRect());
1953         auto area = bounds.area();
1954         if (area.hasOverflowed() || area.unsafeGet() > contextMenuAreaLimit)
1955             continue;
1956
1957         if (bounds.contains(enclosingIntRect(selectionBoundsInRootViewCoordinates)))
1958             continue;
1959
1960         rectsToAvoidInRootViewCoordinates.append(WTFMove(bounds));
1961     }
1962
1963     reply(WTFMove(rectsToAvoidInRootViewCoordinates));
1964 }
1965
1966 void WebPage::getRectsForGranularityWithSelectionOffset(uint32_t granularity, int32_t offset, CallbackID callbackID)
1967 {
1968     Frame& frame = m_page->focusController().focusedOrMainFrame();
1969     VisibleSelection selection = m_storedSelectionForAccessibility.isNone() ? frame.selection().selection() : m_storedSelectionForAccessibility;
1970     VisiblePosition selectionStart = selection.visibleStart();
1971
1972     if (selectionStart.isNull()) {
1973         send(Messages::WebPageProxy::SelectionRectsCallback({ }, callbackID));
1974         return;
1975     }
1976
1977     auto position = visiblePositionForPositionWithOffset(selectionStart, offset);
1978     SelectionDirection direction = offset < 0 ? DirectionBackward : DirectionForward;
1979
1980     auto range = enclosingTextUnitOfGranularity(position, static_cast<WebCore::TextGranularity>(granularity), direction);
1981     if (!range || range->collapsed()) {
1982         send(Messages::WebPageProxy::SelectionRectsCallback({ }, callbackID));
1983         return;
1984     }
1985
1986     Vector<WebCore::SelectionRect> selectionRects;
1987     range->collectSelectionRectsWithoutUnionInteriorLines(selectionRects);
1988     convertSelectionRectsToRootView(frame.view(), selectionRects);
1989     send(Messages::WebPageProxy::SelectionRectsCallback(selectionRects, callbackID));
1990 }
1991
1992 void WebPage::storeSelectionForAccessibility(bool shouldStore)
1993 {
1994     if (!shouldStore)
1995         m_storedSelectionForAccessibility = VisibleSelection();
1996     else {
1997         Frame& frame = m_page->focusController().focusedOrMainFrame();
1998         m_storedSelectionForAccessibility = frame.selection().selection();
1999     }
2000 }
2001
2002 static Optional<SimpleRange> rangeNearPositionMatchesText(const VisiblePosition& position, const String& matchText, const VisibleSelection& selection)
2003 {
2004     auto liveRange = selection.firstRange();
2005     if (!liveRange)
2006         return WTF::nullopt;
2007     SimpleRange range { *liveRange };
2008     auto boundaryPoint = makeBoundaryPoint(position);
2009     if (!boundaryPoint)
2010         return WTF::nullopt;
2011     return findClosestPlainText(range, matchText, { }, characterCount({ range.start, *boundaryPoint }, TextIteratorEmitsCharactersBetweenAllVisiblePositions));
2012 }
2013
2014 void WebPage::getRectsAtSelectionOffsetWithText(int32_t offset, const String& text, CallbackID callbackID)
2015 {
2016     Frame& frame = m_page->focusController().focusedOrMainFrame();
2017     uint32_t length = text.length();
2018     VisibleSelection selection = m_storedSelectionForAccessibility.isNone() ? frame.selection().selection() : m_storedSelectionForAccessibility;
2019     VisiblePosition selectionStart = selection.visibleStart();
2020     VisiblePosition selectionEnd = selection.visibleEnd();
2021
2022     if (selectionStart.isNull() || selectionEnd.isNull()) {
2023         send(Messages::WebPageProxy::SelectionRectsCallback({ }, callbackID));
2024         return;
2025     }
2026
2027     auto startPosition = visiblePositionForPositionWithOffset(selectionStart, offset);
2028     auto endPosition = visiblePositionForPositionWithOffset(startPosition, length);
2029     auto range = Range::create(*frame.document(), startPosition, endPosition);
2030
2031     if (range->collapsed()) {
2032         send(Messages::WebPageProxy::SelectionRectsCallback({ }, callbackID));
2033         return;
2034     }
2035
2036     if (plainTextForDisplay(range.ptr()) != text) {
2037         // Try to search for a range which is the closest to the position within the selection range that matches the passed in text.
2038         if (auto wordRange = rangeNearPositionMatchesText(startPosition, text, selection)) {
2039             if (!wordRange->collapsed())
2040                 range = createLiveRange(*wordRange);
2041         }
2042     }
2043
2044     Vector<WebCore::SelectionRect> selectionRects;
2045     range->collectSelectionRectsWithoutUnionInteriorLines(selectionRects);
2046     convertSelectionRectsToRootView(frame.view(), selectionRects);
2047     send(Messages::WebPageProxy::SelectionRectsCallback(selectionRects, callbackID));
2048 }
2049
2050 VisiblePosition WebPage::visiblePositionInFocusedNodeForPoint(const Frame& frame, const IntPoint& point, bool isInteractingWithFocusedElement)
2051 {
2052     IntPoint adjustedPoint(frame.view()->rootViewToContents(point));
2053     IntPoint constrainedPoint = m_focusedElement && isInteractingWithFocusedElement ? constrainPoint(adjustedPoint, frame, *m_focusedElement) : adjustedPoint;
2054     return frame.visiblePositionForPoint(constrainedPoint);
2055 }
2056
2057 void WebPage::selectPositionAtPoint(const WebCore::IntPoint& point, bool isInteractingWithFocusedElement, CallbackID callbackID)
2058 {
2059     SetForScope<bool> userIsInteractingChange { m_userIsInteracting, true };
2060
2061     auto& frame = m_page->focusController().focusedOrMainFrame();
2062     VisiblePosition position = visiblePositionInFocusedNodeForPoint(frame, point, isInteractingWithFocusedElement);
2063     
2064     if (position.isNotNull())
2065         frame.selection().setSelectedRange(Range::create(*frame.document(), position, position).ptr(), position.affinity(), WebCore::FrameSelection::ShouldCloseTyping::Yes, UserTriggered);
2066     send(Messages::WebPageProxy::VoidCallback(callbackID));
2067 }
2068
2069 void WebPage::selectPositionAtBoundaryWithDirection(const WebCore::IntPoint& point, uint32_t granularity, uint32_t direction, bool isInteractingWithFocusedElement, CallbackID callbackID)
2070 {
2071     auto& frame = m_page->focusController().focusedOrMainFrame();
2072     VisiblePosition position = visiblePositionInFocusedNodeForPoint(frame, point, isInteractingWithFocusedElement);
2073
2074     if (position.isNotNull()) {
2075         position = positionOfNextBoundaryOfGranularity(position, static_cast<WebCore::TextGranularity>(granularity), static_cast<SelectionDirection>(direction));
2076         if (position.isNotNull())
2077             frame.selection().setSelectedRange(Range::create(*frame.document(), position, position).ptr(), UPSTREAM, WebCore::FrameSelection::ShouldCloseTyping::Yes, UserTriggered);
2078     }
2079     send(Messages::WebPageProxy::VoidCallback(callbackID));
2080 }
2081
2082 void WebPage::moveSelectionAtBoundaryWithDirection(uint32_t granularity, uint32_t direction, CallbackID callbackID)
2083 {
2084     Frame& frame = m_page->focusController().focusedOrMainFrame();
2085     
2086     if (!frame.selection().selection().isNone()) {
2087         bool isForward = (direction == DirectionForward || direction == DirectionRight);
2088         VisiblePosition position = (isForward) ? frame.selection().selection().visibleEnd() : frame.selection().selection().visibleStart();
2089         position = positionOfNextBoundaryOfGranularity(position, static_cast<WebCore::TextGranularity>(granularity), static_cast<SelectionDirection>(direction));
2090         if (position.isNotNull())
2091             frame.selection().setSelectedRange(Range::create(*frame.document(), position, position).ptr(), isForward? UPSTREAM : DOWNSTREAM, WebCore::FrameSelection::ShouldCloseTyping::Yes, UserTriggered);
2092     }
2093     send(Messages::WebPageProxy::VoidCallback(callbackID));
2094 }
2095
2096 RefPtr<Range> WebPage::rangeForGranularityAtPoint(Frame& frame, const WebCore::IntPoint& point, uint32_t granularity, bool isInteractingWithFocusedElement)
2097 {
2098     VisiblePosition position = visiblePositionInFocusedNodeForPoint(frame, point, isInteractingWithFocusedElement);
2099
2100     RefPtr<Range> range;
2101     switch (static_cast<WebCore::TextGranularity>(granularity)) {
2102     case CharacterGranularity:
2103         range = makeRange(position, position);
2104         break;
2105     case WordGranularity:
2106         range = wordRangeFromPosition(position);
2107         break;
2108     case SentenceGranularity:
2109         range = enclosingTextUnitOfGranularity(position, SentenceGranularity, DirectionForward);
2110         break;
2111     case ParagraphGranularity:
2112         range = enclosingTextUnitOfGranularity(position, ParagraphGranularity, DirectionForward);
2113         break;
2114     case DocumentGranularity:
2115         // FIXME: It's not clear why this mutates the current selection and returns null.
2116         frame.selection().selectAll();
2117         break;
2118     default:
2119         break;
2120     }
2121     return range;
2122 }
2123
2124 static inline bool rectIsTooBigForSelection(const IntRect& blockRect, const Frame& frame)
2125 {
2126     const float factor = 0.97;
2127     return blockRect.height() > frame.view()->unobscuredContentRect().height() * factor;
2128 }
2129
2130 void WebPage::setFocusedFrameBeforeSelectingTextAtLocation(const IntPoint& point)
2131 {
2132     constexpr OptionSet<HitTestRequest::RequestType> hitType { HitTestRequest::ReadOnly, HitTestRequest::Active, HitTestRequest::DisallowUserAgentShadowContent, HitTestRequest::AllowVisibleChildFrameContentOnly };
2133     auto result = m_page->mainFrame().eventHandler().hitTestResultAtPoint(point, hitType);
2134     auto* hitNode = result.innerNode();
2135     if (hitNode && hitNode->renderer())
2136         m_page->focusController().setFocusedFrame(result.innerNodeFrame());
2137 }
2138
2139 void WebPage::selectTextWithGranularityAtPoint(const WebCore::IntPoint& point, uint32_t granularity, bool isInteractingWithFocusedElement, CallbackID callbackID)
2140 {
2141     setFocusedFrameBeforeSelectingTextAtLocation(point);
2142
2143     auto& frame = m_page->focusController().focusedOrMainFrame();
2144     auto range = rangeForGranularityAtPoint(frame, point, granularity, isInteractingWithFocusedElement);
2145     if (range)
2146         frame.selection().setSelectedRange(range.get(), UPSTREAM, WebCore::FrameSelection::ShouldCloseTyping::Yes, UserTriggered);
2147     m_initialSelection = range;
2148     send(Messages::WebPageProxy::VoidCallback(callbackID));
2149 }
2150
2151 void WebPage::beginSelectionInDirection(uint32_t direction, CallbackID callbackID)
2152 {
2153     m_selectionAnchor = (static_cast<SelectionDirection>(direction) == DirectionLeft) ? Start : End;
2154     send(Messages::WebPageProxy::UnsignedCallback(m_selectionAnchor == Start, callbackID));
2155 }
2156
2157 void WebPage::updateSelectionWithExtentPointAndBoundary(const WebCore::IntPoint& point, uint32_t granularity, bool isInteractingWithFocusedElement, CallbackID callbackID)
2158 {
2159     auto& frame = m_page->focusController().focusedOrMainFrame();
2160     VisiblePosition position = visiblePositionInFocusedNodeForPoint(frame, point, isInteractingWithFocusedElement);
2161     RefPtr<Range> newRange = rangeForGranularityAtPoint(frame, point, granularity, isInteractingWithFocusedElement);
2162     
2163     if (position.isNull() || !m_initialSelection || !newRange) {
2164         send(Messages::WebPageProxy::UnsignedCallback(false, callbackID));
2165         return;
2166     }
2167     
2168     RefPtr<Range> range;
2169     VisiblePosition selectionStart = m_initialSelection->startPosition();
2170     VisiblePosition selectionEnd = m_initialSelection->endPosition();
2171
2172     if (position > m_initialSelection->endPosition())
2173         selectionEnd = newRange->endPosition();
2174     else if (position < m_initialSelection->startPosition())
2175         selectionStart = newRange->startPosition();
2176     
2177     if (selectionStart.isNotNull() && selectionEnd.isNotNull())
2178         range = Range::create(*frame.document(), selectionStart, selectionEnd);
2179     
2180     if (range)
2181         frame.selection().setSelectedRange(range.get(), UPSTREAM, WebCore::FrameSelection::ShouldCloseTyping::Yes, UserTriggered);
2182     
2183     send(Messages::WebPageProxy::UnsignedCallback(selectionStart == m_initialSelection->startPosition(), callbackID));
2184 }
2185
2186 void WebPage::updateSelectionWithExtentPoint(const WebCore::IntPoint& point, bool isInteractingWithFocusedElement, RespectSelectionAnchor respectSelectionAnchor, CallbackID callbackID)
2187 {
2188     auto& frame = m_page->focusController().focusedOrMainFrame();
2189     VisiblePosition position = visiblePositionInFocusedNodeForPoint(frame, point, isInteractingWithFocusedElement);
2190
2191     if (position.isNull()) {
2192         send(Messages::WebPageProxy::UnsignedCallback(false, callbackID));
2193         return;
2194     }
2195
2196     RefPtr<Range> range;
2197     VisiblePosition selectionStart;
2198     VisiblePosition selectionEnd;
2199     
2200     if (respectSelectionAnchor == RespectSelectionAnchor::Yes) {
2201         if (m_selectionAnchor == Start) {
2202             selectionStart = frame.selection().selection().visibleStart();
2203             selectionEnd = position;
2204             if (position <= selectionStart) {
2205                 selectionStart = selectionStart.previous();
2206                 selectionEnd = frame.selection().selection().visibleEnd();
2207                 m_selectionAnchor = End;
2208             }
2209         } else {
2210             selectionStart = position;
2211             selectionEnd = frame.selection().selection().visibleEnd();
2212             if (position >= selectionEnd) {
2213                 selectionStart = frame.selection().selection().visibleStart();
2214                 selectionEnd = selectionEnd.next();
2215                 m_selectionAnchor = Start;
2216             }
2217         }
2218     } else {
2219         auto currentStart = frame.selection().selection().visibleStart();
2220         auto currentEnd = frame.selection().selection().visibleEnd();
2221         if (position <= currentStart) {
2222             selectionStart = position;
2223             selectionEnd = currentEnd;
2224         } else if (position >= currentEnd) {
2225             selectionStart = currentStart;
2226             selectionEnd = position;
2227         }
2228     }
2229     
2230     if (selectionStart.isNotNull() && selectionEnd.isNotNull())
2231         range = Range::create(*frame.document(), selectionStart, selectionEnd);
2232
2233     if (range)
2234         frame.selection().setSelectedRange(range.get(), UPSTREAM, WebCore::FrameSelection::ShouldCloseTyping::Yes, UserTriggered);
2235
2236     send(Messages::WebPageProxy::UnsignedCallback(m_selectionAnchor == Start, callbackID));
2237 }
2238
2239 void WebPage::convertSelectionRectsToRootView(FrameView* view, Vector<SelectionRect>& selectionRects)
2240 {
2241     for (size_t i = 0; i < selectionRects.size(); ++i) {
2242         SelectionRect& currentRect = selectionRects[i];
2243         currentRect.setRect(view->contentsToRootView(currentRect.rect()));
2244     }
2245 }
2246
2247 void WebPage::requestDictationContext(CallbackID callbackID)
2248 {
2249     Frame& frame = m_page->focusController().focusedOrMainFrame();
2250     VisiblePosition startPosition = frame.selection().selection().start();
2251     VisiblePosition endPosition = frame.selection().selection().end();
2252     const unsigned dictationContextWordCount = 5;
2253
2254     String selectedText;
2255     if (frame.selection().isRange())
2256         selectedText = plainTextForContext(frame.selection().selection().toNormalizedRange().get());
2257
2258     String contextBefore;
2259     if (startPosition != startOfEditableContent(startPosition)) {
2260         VisiblePosition currentPosition = startPosition;
2261         VisiblePosition lastPosition = startPosition;
2262         for (unsigned i = 0; i < dictationContextWordCount; ++i) {
2263             currentPosition = startOfWord(positionOfNextBoundaryOfGranularity(lastPosition, WordGranularity, DirectionBackward));
2264             if (currentPosition.isNull())
2265                 break;
2266             lastPosition = currentPosition;
2267         }
2268         if (lastPosition.isNotNull() && lastPosition != startPosition)
2269             contextBefore = plainTextForContext(Range::create(*frame.document(), lastPosition, startPosition).ptr());
2270     }
2271
2272     String contextAfter;
2273     if (endPosition != endOfEditableContent(endPosition)) {
2274         VisiblePosition currentPosition = endPosition;
2275         VisiblePosition lastPosition = endPosition;
2276         for (unsigned i = 0; i < dictationContextWordCount; ++i) {
2277             currentPosition = endOfWord(positionOfNextBoundaryOfGranularity(lastPosition, WordGranularity, DirectionForward));
2278             if (currentPosition.isNull())
2279                 break;
2280             lastPosition = currentPosition;
2281         }
2282         if (lastPosition.isNotNull() && lastPosition != endPosition)
2283             contextAfter = plainTextForContext(Range::create(*frame.document(), endPosition, lastPosition).ptr());
2284     }
2285
2286     send(Messages::WebPageProxy::SelectionContextCallback(selectedText, contextBefore, contextAfter, callbackID));
2287 }
2288
2289 void WebPage::replaceSelectedText(const String& oldText, const String& newText)
2290 {
2291     Frame& frame = m_page->focusController().focusedOrMainFrame();
2292     RefPtr<Range> wordRange = frame.selection().isCaret() ? wordRangeFromPosition(frame.selection().selection().start()) : frame.selection().toNormalizedRange();
2293     if (plainTextForContext(wordRange.get()) != oldText)
2294         return;
2295     
2296     frame.editor().setIgnoreSelectionChanges(true);
2297     frame.selection().setSelectedRange(wordRange.get(), UPSTREAM, WebCore::FrameSelection::ShouldCloseTyping::Yes);
2298     frame.editor().insertText(newText, 0);
2299     frame.editor().setIgnoreSelectionChanges(false);
2300 }
2301
2302 void WebPage::replaceDictatedText(const String& oldText, const String& newText)
2303 {
2304     Frame& frame = m_page->focusController().focusedOrMainFrame();
2305     if (frame.selection().isNone())
2306         return;
2307     
2308     if (frame.selection().isRange()) {
2309         frame.editor().deleteSelectionWithSmartDelete(false);
2310         return;
2311     }
2312     VisiblePosition position = frame.selection().selection().start();
2313     for (size_t i = 0; i < oldText.length(); ++i)
2314         position = position.previous();
2315     if (position.isNull())
2316         position = startOfDocument(static_cast<Node*>(frame.document()->documentElement()));
2317     auto range = Range::create(*frame.document(), position, frame.selection().selection().start());
2318
2319     if (plainTextForContext(range.ptr()) != oldText)
2320         return;
2321
2322     // We don't want to notify the client that the selection has changed until we are done inserting the new text.
2323     frame.editor().setIgnoreSelectionChanges(true);
2324     frame.selection().setSelectedRange(range.ptr(), UPSTREAM, WebCore::FrameSelection::ShouldCloseTyping::Yes);
2325     frame.editor().insertText(newText, 0);
2326     frame.editor().setIgnoreSelectionChanges(false);
2327 }
2328
2329 void WebPage::requestAutocorrectionData(const String& textForAutocorrection, CompletionHandler<void(WebAutocorrectionData)>&& reply)
2330 {
2331     auto& frame = m_page->focusController().focusedOrMainFrame();
2332     if (!frame.selection().isCaret()) {
2333         reply({ });
2334         return;
2335     }
2336
2337     VisiblePosition position = frame.selection().selection().start();
2338     auto range = wordRangeFromPosition(position);
2339     if (!range) {
2340         reply({ });
2341         return;
2342     }
2343
2344     auto textForRange = plainTextForContext(range.get());
2345     const unsigned maxSearchAttempts = 5;
2346     for (size_t i = 0;  i < maxSearchAttempts && textForRange != textForAutocorrection; ++i)
2347     {
2348         position = range->startPosition().previous();
2349         if (position.isNull() || position == range->startPosition())
2350             break;
2351         range = Range::create(*frame.document(), wordRangeFromPosition(position)->startPosition(), range->endPosition());
2352         textForRange = plainTextForContext(range.get());
2353     }
2354
2355     Vector<SelectionRect> selectionRects;
2356     if (textForRange == textForAutocorrection)
2357         range->collectSelectionRects(selectionRects);
2358
2359     Vector<FloatRect> rectsForText;
2360     rectsForText.grow(selectionRects.size());
2361
2362     convertSelectionRectsToRootView(frame.view(), selectionRects);
2363     for (size_t i = 0; i < selectionRects.size(); i++)
2364         rectsForText[i] = selectionRects[i].rect();
2365
2366     bool multipleFonts = false;
2367     CTFontRef font = nil;
2368     if (auto* coreFont = frame.editor().fontForSelection(multipleFonts))
2369         font = coreFont->getCTFont();
2370
2371     reply({ WTFMove(rectsForText), (__bridge UIFont *)font });
2372 }
2373
2374 void WebPage::applyAutocorrection(const String& correction, const String& originalText, CallbackID callbackID)
2375 {
2376     send(Messages::WebPageProxy::StringCallback(applyAutocorrectionInternal(correction, originalText) ? correction : String(), callbackID));
2377 }
2378
2379 Seconds WebPage::eventThrottlingDelay() const
2380 {
2381     auto behaviorOverride = m_page->eventThrottlingBehaviorOverride();
2382     if (behaviorOverride) {
2383         switch (behaviorOverride.value()) {
2384         case EventThrottlingBehavior::Responsive:
2385             return 0_s;
2386         case EventThrottlingBehavior::Unresponsive:
2387             return 1_s;
2388         }
2389     }
2390
2391     if (m_isInStableState || m_estimatedLatency <= Seconds(1.0 / 60))
2392         return 0_s;
2393
2394     return std::min(m_estimatedLatency * 2, 1_s);
2395 }
2396
2397 void WebPage::syncApplyAutocorrection(const String& correction, const String& originalText, CompletionHandler<void(bool)>&& reply)
2398 {
2399     reply(applyAutocorrectionInternal(correction, originalText));
2400 }
2401
2402 bool WebPage::applyAutocorrectionInternal(const String& correction, const String& originalText)
2403 {
2404     auto& frame = m_page->focusController().focusedOrMainFrame();
2405     if (!frame.selection().isCaretOrRange())
2406         return false;
2407
2408     RefPtr<Range> range;
2409     String textForRange;
2410     auto originalTextWithFoldedQuoteMarks = foldQuoteMarks(originalText);
2411
2412     if (frame.selection().isCaret()) {
2413         VisiblePosition position = frame.selection().selection().start();
2414         range = wordRangeFromPosition(position);
2415         textForRange = plainTextForContext(range.get());
2416         
2417         // If 'originalText' is not the same as 'textForRange' we need to move 'range'
2418         // forward such that it matches the original selection as much as possible.
2419         if (foldQuoteMarks(textForRange) != originalTextWithFoldedQuoteMarks) {
2420             // Search for the original text before the selection caret.
2421             for (size_t i = 0; i < originalText.length(); ++i)
2422                 position = position.previous();
2423             if (position.isNull())
2424                 position = startOfDocument(static_cast<Node*>(frame.document()->documentElement()));
2425             range = Range::create(*frame.document(), position, frame.selection().selection().start());
2426             textForRange = plainTextForContext(range.get());
2427             unsigned loopCount = 0;
2428             const unsigned maxPositionsAttempts = 10;
2429             while (textForRange.length() && textForRange.length() > originalText.length() && loopCount < maxPositionsAttempts) {
2430                 position = position.next();
2431                 if (position.isNotNull() && position >= frame.selection().selection().start())
2432                     range = nullptr;
2433                 else
2434                     range = Range::create(*frame.document(), position, frame.selection().selection().start());
2435                 textForRange = plainTextForContext(range.get());
2436                 loopCount++;
2437             }
2438         } else if (textForRange.isEmpty() && range && !range->collapsed()) {
2439             // If 'range' does not include any text but it is not collapsed, we need to set
2440             // 'range' to match the selection. Otherwise non-text nodes will be removed.
2441             range = Range::create(*frame.document(), position, position);
2442             if (!range)
2443                 return false;
2444         }
2445     } else {
2446         // Range selection.
2447         range = frame.selection().toNormalizedRange();
2448         if (!range)
2449             return false;
2450
2451         textForRange = plainTextForContext(range.get());
2452     }
2453
2454     if (foldQuoteMarks(textForRange) != originalTextWithFoldedQuoteMarks)
2455         return false;
2456     
2457     // Correctly determine affinity, using logic currently only present in VisiblePosition
2458     EAffinity affinity = DOWNSTREAM;
2459     if (range && range->collapsed())
2460         affinity = VisiblePosition(range->startPosition(), UPSTREAM).affinity();
2461     
2462     frame.selection().setSelectedRange(range.get(), affinity, WebCore::FrameSelection::ShouldCloseTyping::Yes);
2463     if (correction.length())
2464         frame.editor().insertText(correction, 0, originalText.isEmpty() ? TextEventInputKeyboard : TextEventInputAutocompletion);
2465     else if (originalText.length())
2466         frame.editor().deleteWithDirection(DirectionBackward, CharacterGranularity, false, true);
2467     return true;
2468 }
2469
2470 WebAutocorrectionContext WebPage::autocorrectionContext()
2471 {
2472     String contextBefore;
2473     String markedText;
2474     String selectedText;
2475     String contextAfter;
2476     EditingRange markedTextRange;
2477
2478     auto& frame = m_page->focusController().focusedOrMainFrame();
2479     RefPtr<Range> range;
2480     VisiblePosition startPosition = frame.selection().selection().start();
2481     VisiblePosition endPosition = frame.selection().selection().end();
2482     const unsigned minContextWordCount = 3;
2483     const unsigned minContextLenght = 12;
2484     const unsigned maxContextLength = 30;
2485
2486     if (frame.selection().isRange())
2487         selectedText = plainTextForContext(frame.selection().selection().toNormalizedRange().get());
2488
2489     if (auto compositionRange = frame.editor().compositionRange()) {
2490         range = Range::create(*frame.document(), compositionRange->startPosition(), startPosition);
2491         String markedTextBefore;
2492         if (range)
2493             markedTextBefore = plainTextForContext(range.get());
2494         range = Range::create(*frame.document(), endPosition, compositionRange->endPosition());
2495         String markedTextAfter;
2496         if (range)
2497             markedTextAfter = plainTextForContext(range.get());
2498         markedText = markedTextBefore + selectedText + markedTextAfter;
2499         if (!markedText.isEmpty()) {
2500             markedTextRange.location = markedTextBefore.length();
2501             markedTextRange.length = selectedText.length();
2502         }
2503     } else {
2504         if (startPosition != startOfEditableContent(startPosition)) {
2505             VisiblePosition currentPosition = startPosition;
2506             VisiblePosition previousPosition;
2507             unsigned totalContextLength = 0;
2508             for (unsigned i = 0; i < minContextWordCount; ++i) {
2509                 if (contextBefore.length() >= minContextLenght)
2510                     break;
2511                 previousPosition = startOfWord(positionOfNextBoundaryOfGranularity(currentPosition, WordGranularity, DirectionBackward));
2512                 if (previousPosition.isNull())
2513                     break;
2514                 String currentWord = plainTextForContext(Range::create(*frame.document(), previousPosition, currentPosition).ptr());
2515                 totalContextLength += currentWord.length();
2516                 if (totalContextLength >= maxContextLength)
2517                     break;
2518                 currentPosition = previousPosition;
2519             }
2520             if (currentPosition.isNotNull() && currentPosition != startPosition) {
2521                 contextBefore = plainTextForContext(Range::create(*frame.document(), currentPosition, startPosition).ptr());
2522                 if (atBoundaryOfGranularity(currentPosition, ParagraphGranularity, DirectionBackward))
2523                     contextBefore = makeString("\n "_s, contextBefore);
2524             }
2525         }
2526
2527         if (endPosition != endOfEditableContent(endPosition)) {
2528             VisiblePosition nextPosition;
2529             if (!atBoundaryOfGranularity(endPosition, WordGranularity, DirectionForward) && withinTextUnitOfGranularity(endPosition, WordGranularity, DirectionForward))
2530                 nextPosition = positionOfNextBoundaryOfGranularity(endPosition, WordGranularity, DirectionForward);
2531             if (nextPosition.isNotNull())
2532                 contextAfter = plainTextForContext(Range::create(*frame.document(), endPosition, nextPosition).ptr());
2533         }
2534     }
2535
2536     WebAutocorrectionContext correction;
2537     correction.contextBefore = WTFMove(contextBefore);
2538     correction.markedText = WTFMove(markedText);
2539     correction.selectedText = WTFMove(selectedText);
2540     correction.contextAfter = WTFMove(contextAfter);
2541     correction.markedTextRange = WTFMove(markedTextRange);
2542     return correction;
2543 }
2544
2545 void WebPage::requestAutocorrectionContext()
2546 {
2547     send(Messages::WebPageProxy::HandleAutocorrectionContext(autocorrectionContext()));
2548 }
2549
2550 static HTMLAnchorElement* containingLinkAnchorElement(Element& element)
2551 {
2552     // FIXME: There is code in the drag controller that supports any link, even if it's not an HTMLAnchorElement. Why is this different?
2553     for (auto& currentElement : lineageOfType<HTMLAnchorElement>(element)) {
2554         if (currentElement.isLink())
2555             return &currentElement;
2556     }
2557     return nullptr;
2558 }
2559
2560 static inline bool isAssistableElement(Element& element)
2561 {
2562     if (is<HTMLSelectElement>(element))
2563         return true;
2564     if (is<HTMLTextAreaElement>(element))
2565         return true;
2566     if (is<HTMLImageElement>(element) && downcast<HTMLImageElement>(element).hasEditableImageAttribute())
2567         return true;
2568     if (is<HTMLInputElement>(element)) {
2569         HTMLInputElement& inputElement = downcast<HTMLInputElement>(element);
2570         // FIXME: This laundry list of types is not a good way to factor this. Need a suitable function on HTMLInputElement itself.
2571 #if ENABLE(INPUT_TYPE_COLOR)
2572         if (inputElement.isColorControl())
2573             return true;
2574 #endif
2575         return inputElement.isTextField() || inputElement.isDateField() || inputElement.isDateTimeLocalField() || inputElement.isMonthField() || inputElement.isTimeField();
2576     }
2577     if (is<HTMLIFrameElement>(element))
2578         return false;
2579     return element.isContentEditable();
2580 }
2581
2582 void WebPage::getPositionInformation(const InteractionInformationRequest& request, CompletionHandler<void(InteractionInformationAtPosition&&)>&& reply)
2583 {
2584     // Avoid UIProcess hangs when the WebContent process is stuck on a sync IPC.
2585     if (IPC::UnboundedSynchronousIPCScope::hasOngoingUnboundedSyncIPC()) {
2586         RELEASE_LOG_ERROR_IF_ALLOWED(Process, "getPositionInformation - Not processing because the process is stuck on unbounded sync IPC");
2587         return reply({ });
2588     }
2589
2590     m_pendingSynchronousPositionInformationReply = WTFMove(reply);
2591
2592     auto information = positionInformation(request);
2593
2594     if (auto reply = WTFMove(m_pendingSynchronousPositionInformationReply))
2595         reply(WTFMove(information));
2596 }
2597     
2598 static void focusedElementPositionInformation(WebPage& page, Element& focusedElement, const InteractionInformationRequest& request, InteractionInformationAtPosition& info)
2599 {
2600     const Frame& frame = page.corePage()->focusController().focusedOrMainFrame();
2601     if (!frame.editor().hasComposition())
2602         return;
2603
2604     const uint32_t kHitAreaWidth = 66;
2605     const uint32_t kHitAreaHeight = 66;
2606     FrameView& view = *frame.view();
2607     IntPoint adjustedPoint(view.rootViewToContents(request.point));
2608     IntPoint constrainedPoint = constrainPoint(adjustedPoint, frame, focusedElement);
2609     VisiblePosition position = frame.visiblePositionForPoint(constrainedPoint);
2610
2611     RefPtr<Range> compositionRange = frame.editor().compositionRange();
2612     if (!compositionRange)
2613         return;
2614
2615     if (position < compositionRange->startPosition())
2616         position = compositionRange->startPosition();
2617     else if (position > compositionRange->endPosition())
2618         position = compositionRange->endPosition();
2619     IntRect caretRect = view.contentsToRootView(position.absoluteCaretBounds());
2620     float deltaX = abs(caretRect.x() + (caretRect.width() / 2) - request.point.x());
2621     float deltaYFromTheTop = abs(caretRect.y() - request.point.y());
2622     float deltaYFromTheBottom = abs(caretRect.y() + caretRect.height() - request.point.y());
2623
2624     info.isNearMarkedText = !(deltaX > kHitAreaWidth || deltaYFromTheTop > kHitAreaHeight || deltaYFromTheBottom > kHitAreaHeight);
2625 }
2626
2627 static void linkIndicatorPositionInformation(WebPage& page, Element& linkElement, const InteractionInformationRequest& request, InteractionInformationAtPosition& info)
2628 {
2629     if (!request.includeLinkIndicator)
2630         return;
2631
2632     auto linkRange = rangeOfContents(linkElement);
2633     float deviceScaleFactor = page.corePage()->deviceScaleFactor();
2634     const float marginInPoints = request.linkIndicatorShouldHaveLegacyMargins ? 4 : 0;
2635
2636     auto textIndicator = TextIndicator::createWithRange(linkRange.get(),
2637         TextIndicatorOptionTightlyFitContent | TextIndicatorOptionRespectTextColor | TextIndicatorOptionPaintBackgrounds |
2638         TextIndicatorOptionUseBoundingRectAndPaintAllContentForComplexRanges | TextIndicatorOptionIncludeMarginIfRangeMatchesSelection | TextIndicatorOptionComputeEstimatedBackgroundColor,
2639         TextIndicatorPresentationTransition::None, FloatSize(marginInPoints * deviceScaleFactor, marginInPoints * deviceScaleFactor));
2640         
2641     if (textIndicator)
2642         info.linkIndicator = textIndicator->data();
2643 }
2644     
2645 #if ENABLE(DATA_DETECTION)
2646 static void dataDetectorLinkPositionInformation(Element& element, InteractionInformationAtPosition& info)
2647 {
2648     if (!DataDetection::isDataDetectorLink(element))
2649         return;
2650     
2651     info.isDataDetectorLink = true;
2652     const int dataDetectionExtendedContextLength = 350;
2653     info.dataDetectorIdentifier = DataDetection::dataDetectorIdentifier(element);
2654     info.dataDetectorResults = element.document().frame()->dataDetectionResults();
2655
2656     if (!DataDetection::requiresExtendedContext(element))
2657         return;
2658     
2659     auto linkRange = Range::create(element.document());
2660     linkRange->selectNodeContents(element);
2661     info.textBefore = plainTextForDisplay(rangeExpandedByCharactersInDirectionAtWordBoundary(linkRange->startPosition(),
2662         dataDetectionExtendedContextLength, DirectionBackward).get());
2663     info.textAfter = plainTextForDisplay(rangeExpandedByCharactersInDirectionAtWordBoundary(linkRange->endPosition(),
2664         dataDetectionExtendedContextLength, DirectionForward).get());
2665 }
2666 #endif
2667
2668 static void imagePositionInformation(WebPage& page, Element& element, const InteractionInformationRequest& request, InteractionInformationAtPosition& info)
2669 {
2670     auto& renderImage = downcast<RenderImage>(*(element.renderer()));
2671     if (!renderImage.cachedImage() || renderImage.cachedImage()->errorOccurred())
2672         return;
2673
2674     auto* image = renderImage.cachedImage()->imageForRenderer(&renderImage);
2675     if (!image || image->width() <= 1 || image->height() <= 1)
2676         return;
2677
2678     info.isImage = true;
2679     info.imageURL = element.document().completeURL(renderImage.cachedImage()->url());
2680     info.isAnimatedImage = image->isAnimated();
2681
2682     if (!request.includeSnapshot)
2683         return;
2684
2685     FloatSize screenSizeInPixels = screenSize();
2686     FloatSize imageSize = renderImage.cachedImage()->imageSizeForRenderer(&renderImage);
2687     
2688     screenSizeInPixels.scale(page.corePage()->deviceScaleFactor());
2689     FloatSize scaledSize = largestRectWithAspectRatioInsideRect(imageSize.width() / imageSize.height(), FloatRect(0, 0, screenSizeInPixels.width(), screenSizeInPixels.height())).size();
2690     FloatSize bitmapSize = scaledSize.width() < imageSize.width() ? scaledSize : imageSize;
2691     
2692     // FIXME: Only select ExtendedColor on images known to need wide gamut
2693     ShareableBitmap::Configuration bitmapConfiguration;
2694     bitmapConfiguration.colorSpace.cgColorSpace = screenColorSpace(page.corePage()->mainFrame().view());
2695
2696     auto sharedBitmap = ShareableBitmap::createShareable(IntSize(bitmapSize), bitmapConfiguration);
2697     if (!sharedBitmap)
2698         return;
2699
2700     auto graphicsContext = sharedBitmap->createGraphicsContext();
2701     if (!graphicsContext)
2702         return;
2703
2704     graphicsContext->drawImage(*image, FloatRect(0, 0, bitmapSize.width(), bitmapSize.height()), { renderImage.imageOrientation() });
2705     info.image = sharedBitmap;
2706 }
2707
2708 static void boundsPositionInformation(RenderElement& renderer, InteractionInformationAtPosition& info)
2709 {
2710     if (renderer.isRenderImage())
2711         info.bounds = downcast<RenderImage>(renderer).absoluteContentQuad().enclosingBoundingBox();
2712     else
2713         info.bounds = renderer.absoluteBoundingBoxRect();
2714
2715     if (!renderer.document().frame()->isMainFrame()) {
2716         FrameView *view = renderer.document().frame()->view();
2717         info.bounds = view->contentsToRootView(info.bounds);
2718     }
2719 }
2720
2721 static void elementPositionInformation(WebPage& page, Element& element, const InteractionInformationRequest& request, InteractionInformationAtPosition& info)
2722 {
2723     Element* linkElement = nullptr;
2724     if (element.renderer() && element.renderer()->isRenderImage())
2725         linkElement = containingLinkAnchorElement(element);
2726     else if (element.isLink())
2727         linkElement = &element;
2728
2729     info.isElement = true;
2730     info.idAttribute = element.getIdAttribute();
2731
2732     info.title = element.attributeWithoutSynchronization(HTMLNames::titleAttr).string();
2733     if (linkElement && info.title.isEmpty())
2734         info.title = element.innerText();
2735     if (element.renderer())
2736         info.touchCalloutEnabled = element.renderer()->style().touchCalloutEnabled();
2737
2738     if (linkElement) {
2739         info.isLink = true;
2740         info.url = linkElement->document().completeURL(stripLeadingAndTrailingHTMLSpaces(linkElement->getAttribute(HTMLNames::hrefAttr)));
2741
2742         linkIndicatorPositionInformation(page, *linkElement, request, info);
2743 #if ENABLE(DATA_DETECTION)
2744         dataDetectorLinkPositionInformation(element, info);
2745 #endif
2746     }
2747
2748     auto* elementForScrollTesting = linkElement ? linkElement : &element;
2749     if (auto* renderer = elementForScrollTesting->renderer()) {
2750 #if ENABLE(ASYNC_SCROLLING)
2751         if (auto* scrollingCoordinator = page.scrollingCoordinator())
2752             info.containerScrollingNodeID = scrollingCoordinator->scrollableContainerNodeID(*renderer);
2753 #endif
2754     }
2755
2756     if (auto* renderer = element.renderer()) {
2757         if (renderer->isRenderImage())
2758             imagePositionInformation(page, element, request, info);
2759         boundsPositionInformation(*renderer, info);
2760     }
2761
2762     info.elementContext = page.contextForElement(element);
2763 }
2764     
2765 static void selectionPositionInformation(WebPage& page, const InteractionInformationRequest& request, InteractionInformationAtPosition& info)
2766 {
2767     constexpr OptionSet<HitTestRequest::RequestType> hitType { HitTestRequest::ReadOnly, HitTestRequest::Active, HitTestRequest::DisallowUserAgentShadowContent, HitTestRequest::AllowVisibleChildFrameContentOnly };
2768     HitTestResult result = page.corePage()->mainFrame().eventHandler().hitTestResultAtPoint(request.point, hitType);
2769     Node* hitNode = result.innerNode();
2770
2771     // Hit test could return HTMLHtmlElement that has no renderer, if the body is smaller than the document.
2772     if (!hitNode || !hitNode->renderer())
2773         return;
2774
2775     RenderObject* renderer = hitNode->renderer();
2776     info.bounds = renderer->absoluteBoundingBoxRect(true);
2777     if (is<HTMLAttachmentElement>(*hitNode)) {
2778         info.isAttachment = true;
2779         HTMLAttachmentElement& attachment = downcast<HTMLAttachmentElement>(*hitNode);
2780         info.title = attachment.attachmentTitle();
2781         linkIndicatorPositionInformation(page, attachment, request, info);
2782         if (attachment.file())
2783             info.url = URL::fileURLWithFileSystemPath(downcast<HTMLAttachmentElement>(*hitNode).file()->path());
2784     } else {
2785         info.isSelectable = renderer->style().userSelect() != UserSelect::None;
2786         // We don't want to select blocks that are larger than 97% of the visible area of the document.
2787         // FIXME: Is this heuristic still needed, now that block selection has been removed?
2788         if (info.isSelectable && !hitNode->isTextNode())
2789             info.isSelectable = !isAssistableElement(*downcast<Element>(hitNode)) && !rectIsTooBigForSelection(info.bounds, *result.innerNodeFrame());
2790     }
2791     for (auto currentNode = makeRefPtr(hitNode); currentNode; currentNode = currentNode->parentOrShadowHostNode()) {
2792         auto* renderer = currentNode->renderer();
2793         if (!renderer)
2794             continue;
2795
2796         auto& style = renderer->style();
2797         if (style.userSelect() == UserSelect::None && style.userDrag() == UserDrag::Element) {
2798             info.prefersDraggingOverTextSelection = true;
2799             break;
2800         }
2801     }
2802 #if PLATFORM(MACCATALYST)
2803     bool isInsideFixedPosition;
2804     VisiblePosition caretPosition(renderer->positionForPoint(request.point, nullptr));
2805     info.caretRect = caretPosition.absoluteCaretBounds(&isInsideFixedPosition);
2806 #endif
2807 }
2808
2809 #if ENABLE(DATALIST_ELEMENT)
2810 static void textInteractionPositionInformation(WebPage& page, const HTMLInputElement& input, const InteractionInformationRequest& request, InteractionInformationAtPosition& info)
2811 {
2812     if (!input.list())
2813         return;
2814
2815     constexpr OptionSet<HitTestRequest::RequestType> hitType { HitTestRequest::ReadOnly, HitTestRequest::Active, HitTestRequest::AllowVisibleChildFrameContentOnly };
2816     HitTestResult result = page.corePage()->mainFrame().eventHandler().hitTestResultAtPoint(request.point, hitType);
2817     if (result.innerNode() == input.dataListButtonElement())
2818         info.preventTextInteraction = true;
2819 }
2820 #endif
2821
2822 RefPtr<ShareableBitmap> WebPage::shareableBitmapSnapshotForNode(Element& element)
2823 {
2824     // Ensure that the image contains at most 600K pixels, so that it is not too big.
2825     if (RefPtr<WebImage> snapshot = snapshotNode(element, SnapshotOptionsShareable, 600 * 1024))
2826         return &snapshot->bitmap();
2827     return nullptr;
2828 }
2829
2830 static bool canForceCaretForPosition(const VisiblePosition& position)
2831 {
2832     auto* node = position.deepEquivalent().anchorNode();
2833     if (!node)
2834         return false;
2835
2836     auto* renderer = node->renderer();
2837     auto* style = renderer ? &renderer->style() : nullptr;
2838     auto cursorType = style ? style->cursor() : CursorType::Auto;
2839
2840     if (cursorType == CursorType::Text)
2841         return true;
2842
2843     if (cursorType != CursorType::Auto)
2844         return false;
2845
2846     if (node->hasEditableStyle())
2847         return true;
2848
2849     if (!renderer)
2850         return false;
2851
2852     return renderer->isText() && node->canStartSelection();
2853 }
2854
2855 static void populateCaretContext(const HitTestResult& hitTestResult, const InteractionInformationRequest& request, InteractionInformationAtPosition& info)
2856 {
2857     auto frame = makeRefPtr(hitTestResult.innerNodeFrame());
2858     if (!frame)
2859         return;
2860
2861     auto view = makeRefPtr(frame->view());
2862     if (!view)
2863         return;
2864
2865     auto node = hitTestResult.innerNode();
2866     if (!node)
2867         return;
2868
2869     auto* renderer = node->renderer();
2870     if (!renderer)
2871         return;
2872
2873     while (renderer && !is<RenderBlockFlow>(*renderer))
2874         renderer = renderer->parent();
2875
2876     if (!renderer)
2877         return;
2878
2879     // FIXME: We should be able to retrieve this geometry information without
2880     // forcing the text to fall out of Simple Line Layout.
2881     auto& blockFlow = downcast<RenderBlockFlow>(*renderer);
2882     auto position = frame->visiblePositionForPoint(view->rootViewToContents(request.point));
2883     auto lineRect = position.absoluteSelectionBoundsForLine();
2884     bool isEditable = node->hasEditableStyle();
2885
2886     if (isEditable)
2887         lineRect.setWidth(blockFlow.contentWidth());
2888
2889     info.lineCaretExtent = view->contentsToRootView(lineRect);
2890     info.caretHeight = info.lineCaretExtent.height();
2891
2892     bool lineContainsRequestPoint = info.lineCaretExtent.contains(request.point);
2893     // Force an I-beam cursor if the page didn't request a hand, and we're inside the bounds of the line.
2894     if (lineContainsRequestPoint && info.cursor->type() != Cursor::Hand && canForceCaretForPosition(position))
2895         info.cursor = Cursor::fromType(Cursor::IBeam);
2896
2897     if (!lineContainsRequestPoint && info.cursor->type() == Cursor::IBeam) {
2898         auto approximateLineRectInContentCoordinates = renderer->absoluteBoundingBoxRect();
2899         approximateLineRectInContentCoordinates.setHeight(renderer->style().computedLineHeight());
2900         info.lineCaretExtent = view->contentsToRootView(approximateLineRectInContentCoordinates);
2901         if (!info.lineCaretExtent.contains(request.point) || !isEditable)
2902             info.lineCaretExtent.setY(request.point.y() - info.lineCaretExtent.height() / 2);
2903         info.caretHeight = info.lineCaretExtent.height();
2904     }
2905
2906     auto nodeShouldNotUseIBeam = ^(Node* node) {
2907         if (!node)
2908             return false;
2909         RenderObject *renderer = node->renderer();
2910         if (!renderer)
2911             return false;
2912         return is<RenderReplaced>(*renderer);
2913     };
2914
2915     const auto& deepPosition = position.deepEquivalent();
2916     info.shouldNotUseIBeamInEditableContent = nodeShouldNotUseIBeam(node) || nodeShouldNotUseIBeam(deepPosition.computeNodeBeforePosition()) || nodeShouldNotUseIBeam(deepPosition.computeNodeAfterPosition());
2917 }
2918
2919 InteractionInformationAtPosition WebPage::positionInformation(const InteractionInformationRequest& request)
2920 {
2921     InteractionInformationAtPosition info;
2922     info.request = request;
2923
2924     FloatPoint adjustedPoint;
2925     auto* nodeRespondingToClickEvents = m_page->mainFrame().nodeRespondingToClickEvents(request.point, adjustedPoint);
2926
2927     info.adjustedPointForNodeRespondingToClickEvents = adjustedPoint;
2928     info.nodeAtPositionHasDoubleClickHandler = m_page->mainFrame().nodeRespondingToDoubleClickEvent(request.point, adjustedPoint);
2929
2930     auto& eventHandler = m_page->mainFrame().eventHandler();
2931     constexpr OptionSet<HitTestRequest::RequestType> hitType { HitTestRequest::ReadOnly, HitTestRequest::AllowFrameScrollbars, HitTestRequest::AllowVisibleChildFrameContentOnly };
2932     HitTestResult hitTestResultForCursor = eventHandler.hitTestResultAtPoint(request.point, hitType);
2933     if (auto* hitFrame = hitTestResultForCursor.innerNodeFrame()) {
2934         info.cursor = hitFrame->eventHandler().selectCursor(hitTestResultForCursor, false);
2935         if (request.includeCaretContext)
2936             populateCaretContext(hitTestResultForCursor, request, info);
2937     }
2938
2939     if (m_focusedElement)
2940         focusedElementPositionInformation(*this, *m_focusedElement, request, info);
2941
2942     if (is<Element>(nodeRespondingToClickEvents)) {
2943         auto& element = downcast<Element>(*nodeRespondingToClickEvents);
2944         elementPositionInformation(*this, element, request, info);
2945
2946         if (info.isLink && !info.isImage && request.includeSnapshot)
2947             info.image = shareableBitmapSnapshotForNode(element);
2948     }
2949
2950     if (!(info.isLink || info.isImage))
2951         selectionPositionInformation(*this, request, info);
2952
2953     // Prevent the callout bar from showing when tapping on the datalist button.
2954 #if ENABLE(DATALIST_ELEMENT)
2955     if (is<HTMLInputElement>(nodeRespondingToClickEvents))
2956         textInteractionPositionInformation(*this, downcast<HTMLInputElement>(*nodeRespondingToClickEvents), request, info);
2957 #endif
2958
2959     return info;
2960 }
2961
2962 void WebPage::requestPositionInformation(const InteractionInformationRequest& request)
2963 {
2964     send(Messages::WebPageProxy::DidReceivePositionInformation(positionInformation(request)));
2965 }
2966
2967 void WebPage::startInteractionWithElementContextOrPosition(Optional<WebCore::ElementContext>&& elementContext, WebCore::IntPoint&& point)
2968 {
2969     if (elementContext) {
2970         m_interactionNode = elementForContext(*elementContext);
2971         if (m_interactionNode)
2972             return;
2973     }
2974
2975     FloatPoint adjustedPoint;
2976     m_interactionNode = m_page->mainFrame().nodeRespondingToInteraction(point, adjustedPoint);
2977 }
2978
2979 void WebPage::stopInteraction()
2980 {
2981     m_interactionNode = nullptr;
2982 }
2983
2984 void WebPage::performActionOnElement(uint32_t action)
2985 {
2986     if (!is<HTMLElement>(m_interactionNode.get()))
2987         return;
2988
2989     HTMLElement& element = downcast<HTMLElement>(*m_interactionNode);
2990     if (!element.renderer())
2991         return;
2992
2993     if (static_cast<SheetAction>(action) == SheetAction::Copy) {
2994         if (is<RenderImage>(*element.renderer())) {
2995             URL url;
2996             String title;
2997             if (auto* linkElement = containingLinkAnchorElement(element)) {
2998                 url = linkElement->href();
2999                 title = linkElement->attributeWithoutSynchronization(HTMLNames::titleAttr);
3000                 if (!title.length())
3001                     title = linkElement->textContent();
3002                 title = stripLeadingAndTrailingHTMLSpaces(title);
3003             }
3004             m_interactionNode->document().frame()->editor().writeImageToPasteboard(*Pasteboard::createForCopyAndPaste(), element, url, title);
3005         } else if (element.isLink()) {
3006             m_interactionNode->document().frame()->editor().copyURL(element.document().completeURL(stripLeadingAndTrailingHTMLSpaces(element.attributeWithoutSynchronization(HTMLNames::hrefAttr))), element.textContent());
3007         }
3008     } else if (static_cast<SheetAction>(action) == SheetAction::SaveImage) {
3009         if (!is<RenderImage>(*element.renderer()))
3010             return;
3011         CachedImage* cachedImage = downcast<RenderImage>(*element.renderer()).cachedImage();
3012         if (!cachedImage)
3013             return;
3014         RefPtr<SharedBuffer> buffer = cachedImage->resourceBuffer();
3015         if (!buffer)
3016             return;
3017         uint64_t bufferSize = buffer->size();
3018         RefPtr<SharedMemory> sharedMemoryBuffer = SharedMemory::allocate(bufferSize);
3019         memcpy(sharedMemoryBuffer->data(), buffer->data(), bufferSize);
3020         SharedMemory::Handle handle;
3021         sharedMemoryBuffer->createHandle(handle, SharedMemory::Protection::ReadOnly);
3022         send(Messages::WebPageProxy::SaveImageToLibrary(handle, bufferSize));
3023     }
3024 }
3025
3026 static inline Element* nextAssistableElement(Node* startNode, Page& page, bool isForward)
3027 {
3028     if (!is<Element>(startNode))
3029         return nullptr;
3030
3031     Element* nextElement = downcast<Element>(startNode);
3032     do {
3033         nextElement = isForward
3034             ? page.focusController().nextFocusableElement(*nextElement)
3035             : page.focusController().previousFocusableElement(*nextElement);
3036     } while (nextElement && !isAssistableElement(*nextElement));
3037
3038     return nextElement;
3039 }
3040
3041 void WebPage::focusNextFocusedElement(bool isForward, CallbackID callbackID)
3042 {
3043     Element* nextElement = nextAssistableElement(m_focusedElement.get(), *m_page, isForward);
3044     m_userIsInteracting = true;
3045     if (nextElement)
3046         nextElement->focus();
3047     m_userIsInteracting = false;
3048     send(Messages::WebPageProxy::VoidCallback(callbackID));
3049 }
3050
3051 void WebPage::getFocusedElementInformation(FocusedElementInformation& information)
3052 {
3053     RefPtr<Document> document = m_page->focusController().focusedOrMainFrame().document();
3054     if (!document || !document->view())
3055         return;
3056
3057     auto focusedElement = m_focusedElement.copyRef();
3058     bool willLayout = document->view()->needsLayout();
3059     layoutIfNeeded();
3060
3061     // Layout may have detached the document or caused a change of focus.
3062     if (!document->view() || focusedElement != m_focusedElement)
3063         return;
3064
3065     if (willLayout)
3066         sendEditorStateUpdate();
3067     else
3068         scheduleFullEditorStateUpdate();
3069
3070     information.lastInteractionLocation = m_lastInteractionLocation;
3071     if (auto elementContext = contextForElement(*focusedElement))
3072         information.elementContext = WTFMove(*elementContext);
3073
3074     if (auto* renderer = focusedElement->renderer()) {
3075         information.interactionRect = rootViewInteractionBoundsForElement(*focusedElement);
3076         information.nodeFontSize = renderer->style().fontDescription().computedSize();
3077
3078         bool inFixed = false;
3079         renderer->localToContainerPoint(FloatPoint(), nullptr, UseTransforms, &inFixed);
3080         information.insideFixedPosition = inFixed;
3081         information.isRTL = renderer->style().direction() == TextDirection::RTL;
3082     } else
3083         information.interactionRect = { };
3084
3085     if (is<HTMLElement>(focusedElement))
3086         information.isSpellCheckingEnabled = downcast<HTMLElement>(*focusedElement).spellcheck();
3087
3088     information.minimumScaleFactor = minimumPageScaleFactor();
3089     information.maximumScaleFactor = maximumPageScaleFactor();
3090     information.maximumScaleFactorIgnoringAlwaysScalable = maximumPageScaleFactorIgnoringAlwaysScalable();
3091     information.allowsUserScaling = m_viewportConfiguration.allowsUserScaling();
3092     information.allowsUserScalingIgnoringAlwaysScalable = m_viewportConfiguration.allowsUserScalingIgnoringAlwaysScalable();
3093     if (auto* nextElement = nextAssistableElement(focusedElement.get(), *m_page, true)) {
3094         information.nextNodeRect = rootViewBoundsForElement(*nextElement);
3095         information.hasNextNode = true;
3096     }
3097     if (auto* previousElement = nextAssistableElement(focusedElement.get(), *m_page, false)) {
3098         information.previousNodeRect = rootViewBoundsForElement(*previousElement);
3099         information.hasPreviousNode = true;
3100     }
3101     information.focusedElementIdentifier = m_currentFocusedElementIdentifier;
3102
3103     if (is<LabelableElement>(*focusedElement)) {
3104         auto labels = downcast<LabelableElement>(*focusedElement).labels();
3105         Vector<Ref<Element>> associatedLabels;
3106         for (unsigned index = 0; index < labels->length(); ++index) {
3107             if (is<Element>(labels->item(index)) && labels->item(index)->renderer())
3108                 associatedLabels.append(downcast<Element>(*labels->item(index)));
3109         }
3110         for (auto& labelElement : associatedLabels) {
3111             auto text = labelElement->innerText();
3112             if (!text.isEmpty()) {
3113                 information.label = WTFMove(text);
3114                 break;
3115             }
3116         }
3117     }
3118
3119     information.title = focusedElement->title();
3120     information.ariaLabel = focusedElement->attributeWithoutSynchronization(HTMLNames::aria_labelAttr);
3121
3122     if (is<HTMLSelectElement>(*focusedElement)) {
3123         HTMLSelectElement& element = downcast<HTMLSelectElement>(*focusedElement);
3124         information.elementType = InputType::Select;
3125         const Vector<HTMLElement*>& items = element.listItems();
3126         size_t count = items.size();
3127         int parentGroupID = 0;
3128         // The parent group ID indicates the group the option belongs to and is 0 for group elements.
3129         // If there are option elements in between groups, they are given it's own group identifier.
3130         // If a select does not have groups, all the option elements have group ID 0.
3131         for (size_t i = 0; i < count; ++i) {
3132             HTMLElement* item = items[i];
3133             if (is<HTMLOptionElement>(*item)) {
3134                 HTMLOptionElement& option = downcast<HTMLOptionElement>(*item);
3135                 information.selectOptions.append(OptionItem(option.text(), false, parentGroupID, option.selected(), option.hasAttributeWithoutSynchronization(WebCore::HTMLNames::disabledAttr)));
3136             } else if (is<HTMLOptGroupElement>(*item)) {
3137                 HTMLOptGroupElement& group = downcast<HTMLOptGroupElement>(*item);
3138                 parentGroupID++;
3139                 information.selectOptions.append(OptionItem(group.groupLabelText(), true, 0, false, group.hasAttributeWithoutSynchronization(WebCore::HTMLNames::disabledAttr)));
3140             }
3141         }
3142         information.selectedIndex = element.selectedIndex();
3143         information.isMultiSelect = element.multiple();
3144     } else if (is<HTMLTextAreaElement>(*focusedElement)) {
3145         HTMLTextAreaElement& element = downcast<HTMLTextAreaElement>(*focusedElement);
3146         information.autocapitalizeType = element.autocapitalizeType();
3147         information.isAutocorrect = element.shouldAutocorrect();
3148         information.elementType = InputType::TextArea;
3149         information.isReadOnly = element.isReadOnly();
3150         information.value = element.value();
3151         information.autofillFieldName = WebCore::toAutofillFieldName(element.autofillData().fieldName);
3152         information.placeholder = element.attributeWithoutSynchronization(HTMLNames::placeholderAttr);
3153         information.inputMode = element.canonicalInputMode();
3154         information.enterKeyHint = element.canonicalEnterKeyHint();
3155     } else if (is<HTMLInputElement>(*focusedElement)) {
3156         HTMLInputElement& element = downcast<HTMLInputElement>(*focusedElement);
3157         HTMLFormElement* form = element.form();
3158         if (form)
3159             information.formAction = form->getURLAttribute(WebCore::HTMLNames::actionAttr);
3160         if (auto autofillElements = WebCore::AutofillElements::computeAutofillElements(element)) {
3161             information.acceptsAutofilledLoginCredentials = true;
3162             information.isAutofillableUsernameField = autofillElements->username() == focusedElement;
3163         }
3164         information.representingPageURL = element.document().urlForBindings();
3165         information.autocapitalizeType = element.autocapitalizeType();
3166         information.isAutocorrect = element.shouldAutocorrect();
3167         information.placeholder = element.attributeWithoutSynchronization(HTMLNames::placeholderAttr);
3168         if (element.isPasswordField())
3169             information.elementType = InputType::Password;
3170         else if (element.isSearchField())
3171             information.elementType = InputType::Search;
3172         else if (element.isEmailField())
3173             information.elementType = InputType::Email;
3174         else if (element.isTelephoneField())
3175             information.elementType = InputType::Phone;
3176         else if (element.isNumberField())
3177             information.elementType = element.getAttribute("pattern") == "\\d*" || element.getAttribute("pattern") == "[0-9]*" ? InputType::NumberPad : InputType::Number;
3178         else if (element.isDateTimeLocalField())
3179             information.elementType = InputType::DateTimeLocal;
3180         else if (element.isDateField())
3181             information.elementType = InputType::Date;
3182         else if (element.isDateTimeField())
3183             information.elementType = InputType::DateTime;
3184         else if (element.isTimeField())
3185             information.elementType = InputType::Time;
3186         else if (element.isWeekField())
3187             information.elementType = InputType::Week;
3188         else if (element.isMonthField())
3189             information.elementType = InputType::Month;
3190         else if (element.isURLField())
3191             information.elementType = InputType::URL;
3192         else if (element.isText()) {
3193             const AtomString& pattern = element.attributeWithoutSynchronization(HTMLNames::patternAttr);
3194             if (pattern == "\\d*" || pattern == "[0-9]*")
3195                 information.elementType = InputType::NumberPad;
3196             else {
3197                 information.elementType = InputType::Text;
3198                 if (!information.formAction.isEmpty()
3199                     && (element.getNameAttribute().contains("search") || element.getIdAttribute().contains("search") || element.attributeWithoutSynchronization(HTMLNames::titleAttr).contains("search")))
3200                     information.elementType = InputType::Search;
3201             }
3202         }
3203 #if ENABLE(INPUT_TYPE_COLOR)
3204         else if (element.isColorControl()) {
3205             information.elementType = InputType::Color;
3206 #if ENABLE(DATALIST_ELEMENT)
3207             information.suggestedColors = element.suggestedColors();
3208 #endif
3209         }
3210 #endif
3211
3212 #if ENABLE(DATALIST_ELEMENT)
3213         information.hasSuggestions = !!element.list();
3214 #endif
3215         information.inputMode = element.canonicalInputMode();
3216         information.enterKeyHint = element.canonicalEnterKeyHint();
3217         information.isReadOnly = element.isReadOnly();
3218         information.value = element.value();
3219         information.valueAsNumber = element.valueAsNumber();
3220         information.autofillFieldName = WebCore::toAutofillFieldName(element.autofillData().fieldName);
3221     } else if (is<HTMLImageElement>(*focusedElement) && downcast<HTMLImageElement>(*focusedElement).hasEditableImageAttribute()) {
3222         information.elementType = InputType::Drawing;
3223         information.embeddedViewID = downcast<HTMLImageElement>(*focusedElement).editableImageViewID();
3224     } else if (focusedElement->hasEditableStyle()) {
3225         information.elementType = InputType::ContentEditable;
3226         if (is<HTMLElement>(*focusedElement)) {
3227             auto& focusedHTMLElement = downcast<HTMLElement>(*focusedElement);
3228             information.isAutocorrect = focusedHTMLElement.shouldAutocorrect();
3229             information.autocapitalizeType = focusedHTMLElement.autocapitalizeType();
3230             information.inputMode = focusedHTMLElement.canonicalInputMode();
3231             information.enterKeyHint = focusedHTMLElement.canonicalEnterKeyHint();
3232             information.shouldSynthesizeKeyEventsForEditing = focusedHTMLElement.document().settings().syntheticEditingCommandsEnabled();
3233         } else {
3234             information.isAutocorrect = true;
3235             information.autocapitalizeType = AutocapitalizeTypeDefault;
3236         }
3237         information.isReadOnly = false;
3238     }
3239
3240     if (focusedElement->document().quirks().shouldSuppressAutocorrectionAndAutocaptializationInHiddenEditableAreas() && isTransparentOrFullyClipped(*focusedElement)) {
3241         information.autocapitalizeType =&nbs