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