Switch from PLATFORM(IOS) to PLATFORM(IOS_FAMILY)
[WebKit-https.git] / Source / WebKit / WebProcess / WebPage / ios / WebPageIOS.mm
1 /*
2  * Copyright (C) 2012-2018 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "WebPage.h"
28
29 #if PLATFORM(IOS_FAMILY)
30
31 #import "AccessibilityIOS.h"
32 #import "AssistedNodeInformation.h"
33 #import "DataReference.h"
34 #import "DrawingArea.h"
35 #import "EditingRange.h"
36 #import "EditorState.h"
37 #import "GestureTypes.h"
38 #import "InteractionInformationAtPosition.h"
39 #import "Logging.h"
40 #import "NativeWebKeyboardEvent.h"
41 #import "PluginView.h"
42 #import "PrintInfo.h"
43 #import "RemoteLayerTreeDrawingArea.h"
44 #import "SandboxUtilities.h"
45 #import "UserData.h"
46 #import "VisibleContentRectUpdateInfo.h"
47 #import "WKAccessibilityWebPageObjectIOS.h"
48 #import "WebChromeClient.h"
49 #import "WebCoreArgumentCoders.h"
50 #import "WebFrame.h"
51 #import "WebImage.h"
52 #import "WebPageProxyMessages.h"
53 #import "WebPreviewLoaderClient.h"
54 #import "WebProcess.h"
55 #import <CoreText/CTFont.h>
56 #import <WebCore/Autofill.h>
57 #import <WebCore/AutofillElements.h>
58 #import <WebCore/Chrome.h>
59 #import <WebCore/DataDetection.h>
60 #import <WebCore/DiagnosticLoggingClient.h>
61 #import <WebCore/DiagnosticLoggingKeys.h>
62 #import <WebCore/DragController.h>
63 #import <WebCore/Editing.h>
64 #import <WebCore/Editor.h>
65 #import <WebCore/Element.h>
66 #import <WebCore/ElementAncestorIterator.h>
67 #import <WebCore/EventHandler.h>
68 #import <WebCore/File.h>
69 #import <WebCore/FloatQuad.h>
70 #import <WebCore/FocusController.h>
71 #import <WebCore/Frame.h>
72 #import <WebCore/FrameLoaderClient.h>
73 #import <WebCore/FrameView.h>
74 #import <WebCore/GeometryUtilities.h>
75 #import <WebCore/HTMLAreaElement.h>
76 #import <WebCore/HTMLAttachmentElement.h>
77 #import <WebCore/HTMLBodyElement.h>
78 #import <WebCore/HTMLElement.h>
79 #import <WebCore/HTMLElementTypeHelpers.h>
80 #import <WebCore/HTMLFormElement.h>
81 #import <WebCore/HTMLImageElement.h>
82 #import <WebCore/HTMLInputElement.h>
83 #import <WebCore/HTMLOptGroupElement.h>
84 #import <WebCore/HTMLOptionElement.h>
85 #import <WebCore/HTMLParserIdioms.h>
86 #import <WebCore/HTMLSelectElement.h>
87 #import <WebCore/HTMLTextAreaElement.h>
88 #import <WebCore/HTMLTextFormControlElement.h>
89 #import <WebCore/HistoryItem.h>
90 #import <WebCore/HitTestResult.h>
91 #import <WebCore/InputMode.h>
92 #import <WebCore/KeyboardEvent.h>
93 #import <WebCore/LibWebRTCProvider.h>
94 #import <WebCore/MediaSessionManagerIOS.h>
95 #import <WebCore/Node.h>
96 #import <WebCore/NodeList.h>
97 #import <WebCore/NotImplemented.h>
98 #import <WebCore/Page.h>
99 #import <WebCore/Pasteboard.h>
100 #import <WebCore/PlatformKeyboardEvent.h>
101 #import <WebCore/PlatformMouseEvent.h>
102 #import <WebCore/RenderBlock.h>
103 #import <WebCore/RenderImage.h>
104 #import <WebCore/RenderThemeIOS.h>
105 #import <WebCore/RenderView.h>
106 #import <WebCore/RuntimeApplicationChecks.h>
107 #import <WebCore/Settings.h>
108 #import <WebCore/SharedBuffer.h>
109 #import <WebCore/StyleProperties.h>
110 #import <WebCore/TextIndicator.h>
111 #import <WebCore/TextIterator.h>
112 #import <WebCore/VisibleUnits.h>
113 #import <WebCore/WKContentObservation.h>
114 #import <WebCore/WebEvent.h>
115 #import <wtf/MathExtras.h>
116 #import <wtf/MemoryPressureHandler.h>
117 #import <wtf/SetForScope.h>
118 #import <wtf/SoftLinking.h>
119 #import <wtf/cocoa/Entitlements.h>
120 #import <wtf/text/TextStream.h>
121
122 #if ENABLE(MEDIA_STREAM)
123 #import "CelestialSPI.h"
124 SOFT_LINK_PRIVATE_FRAMEWORK_OPTIONAL(Celestial)
125 SOFT_LINK_CLASS_OPTIONAL(Celestial, AVSystemController)
126 SOFT_LINK_CONSTANT_MAY_FAIL(Celestial, AVSystemController_PIDToInheritApplicationStateFrom, NSString *)
127 #endif
128
129 namespace WebKit {
130 using namespace WebCore;
131
132 const int blockSelectionStartWidth = 100;
133 const int blockSelectionStartHeight = 100;
134
135 void WebPage::platformInitialize()
136 {
137     platformInitializeAccessibility();
138 }
139
140 void WebPage::platformDetach()
141 {
142     [m_mockAccessibilityElement setWebPage:nullptr];
143 }
144     
145 void WebPage::platformInitializeAccessibility()
146 {
147     m_mockAccessibilityElement = adoptNS([[WKAccessibilityWebPageObject alloc] init]);
148     [m_mockAccessibilityElement setWebPage:this];
149     
150     NSData *remoteToken = newAccessibilityRemoteToken([NSUUID UUID]);
151     IPC::DataReference dataToken = IPC::DataReference(reinterpret_cast<const uint8_t*>([remoteToken bytes]), [remoteToken length]);
152     send(Messages::WebPageProxy::RegisterWebProcessAccessibilityToken(dataToken));
153 }
154
155 static void computeEditableRootHasContentAndPlainText(const VisibleSelection& selection, EditorState::PostLayoutData& data)
156 {
157     data.hasContent = false;
158     data.hasPlainText = false;
159     if (!selection.isContentEditable())
160         return;
161
162     if (data.selectedTextLength || data.characterAfterSelection || data.characterBeforeSelection || data.twoCharacterBeforeSelection) {
163         // 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.
164         data.hasContent = true;
165         data.hasPlainText = true;
166         return;
167     }
168
169     auto* root = selection.rootEditableElement();
170     if (!root)
171         return;
172
173     auto startInEditableRoot = firstPositionInNode(root);
174     data.hasContent = root->hasChildNodes() && !isEndOfEditableOrNonEditableContent(startInEditableRoot);
175     data.hasPlainText = data.hasContent && hasAnyPlainText(Range::create(root->document(), VisiblePosition { startInEditableRoot }, VisiblePosition { lastPositionInNode(root) }));
176 }
177
178 void WebPage::platformEditorState(Frame& frame, EditorState& result, IncludePostLayoutDataHint shouldIncludePostLayoutData) const
179 {
180     if (frame.editor().hasComposition()) {
181         RefPtr<Range> compositionRange = frame.editor().compositionRange();
182         Vector<WebCore::SelectionRect> compositionRects;
183         if (compositionRange) {
184             compositionRange->collectSelectionRects(compositionRects);
185             if (compositionRects.size())
186                 result.firstMarkedRect = compositionRects[0].rect();
187             if (compositionRects.size() > 1)
188                 result.lastMarkedRect = compositionRects.last().rect();
189             else
190                 result.lastMarkedRect = result.firstMarkedRect;
191             result.markedText = plainTextReplacingNoBreakSpace(compositionRange.get());
192         }
193     }
194
195     // We only set the remaining EditorState entries if layout is done as a performance optimization
196     // to avoid the need to force a synchronous layout here to compute these entries. If we
197     // have a composition or are using a hardware keyboard then we send the full editor state
198     // immediately so that the UIProcess can update UI, including the position of the caret.
199     bool needsLayout = !frame.view() || frame.view()->needsLayout();
200     if (shouldIncludePostLayoutData == IncludePostLayoutDataHint::No && needsLayout && !isInHardwareKeyboardMode() && !frame.editor().hasComposition()) {
201         result.isMissingPostLayoutData = true;
202         return;
203     }
204
205     auto& postLayoutData = result.postLayoutData();
206     FrameView* view = frame.view();
207     const VisibleSelection& selection = frame.selection().selection();
208     postLayoutData.isStableStateUpdate = m_isInStableState;
209     bool startNodeIsInsideFixedPosition = false;
210     bool endNodeIsInsideFixedPosition = false;
211     if (selection.isCaret()) {
212         postLayoutData.caretRectAtStart = view->contentsToRootView(frame.selection().absoluteCaretBounds(&startNodeIsInsideFixedPosition));
213         endNodeIsInsideFixedPosition = startNodeIsInsideFixedPosition;
214         postLayoutData.caretRectAtEnd = postLayoutData.caretRectAtStart;
215         // FIXME: The following check should take into account writing direction.
216         postLayoutData.isReplaceAllowed = result.isContentEditable && atBoundaryOfGranularity(selection.start(), WordGranularity, DirectionForward);
217         postLayoutData.wordAtSelection = plainTextReplacingNoBreakSpace(wordRangeFromPosition(selection.start()).get());
218         if (selection.isContentEditable())
219             charactersAroundPosition(selection.start(), postLayoutData.characterAfterSelection, postLayoutData.characterBeforeSelection, postLayoutData.twoCharacterBeforeSelection);
220     } else if (selection.isRange()) {
221         postLayoutData.caretRectAtStart = view->contentsToRootView(VisiblePosition(selection.start()).absoluteCaretBounds(&startNodeIsInsideFixedPosition));
222         postLayoutData.caretRectAtEnd = view->contentsToRootView(VisiblePosition(selection.end()).absoluteCaretBounds(&endNodeIsInsideFixedPosition));
223         RefPtr<Range> selectedRange = selection.toNormalizedRange();
224         String selectedText;
225         if (selectedRange) {
226             selectedRange->collectSelectionRects(postLayoutData.selectionRects);
227             convertSelectionRectsToRootView(view, postLayoutData.selectionRects);
228             selectedText = plainTextReplacingNoBreakSpace(selectedRange.get(), TextIteratorDefaultBehavior, true);
229             postLayoutData.selectedTextLength = selectedText.length();
230             const int maxSelectedTextLength = 200;
231             if (selectedText.length() <= maxSelectedTextLength)
232                 postLayoutData.wordAtSelection = selectedText;
233         }
234         // FIXME: We should disallow replace when the string contains only CJ characters.
235         postLayoutData.isReplaceAllowed = result.isContentEditable && !result.isInPasswordField && !selectedText.isAllSpecialCharacters<isHTMLSpace>();
236     }
237     postLayoutData.insideFixedPosition = startNodeIsInsideFixedPosition || endNodeIsInsideFixedPosition;
238     if (!selection.isNone()) {
239         if (m_assistedNode && m_assistedNode->renderer()) {
240             postLayoutData.selectionClipRect = view->contentsToRootView(m_assistedNode->renderer()->absoluteBoundingBoxRect());
241             postLayoutData.caretColor = m_assistedNode->renderer()->style().caretColor();
242         }
243         computeEditableRootHasContentAndPlainText(selection, postLayoutData);
244     }
245 }
246
247 FloatSize WebPage::screenSize() const
248 {
249     return m_screenSize;
250 }
251
252 FloatSize WebPage::availableScreenSize() const
253 {
254     return m_availableScreenSize;
255 }
256
257 FloatSize WebPage::overrideScreenSize() const
258 {
259     return m_overrideScreenSize;
260 }
261
262 void WebPage::didReceiveMobileDocType(bool isMobileDoctype)
263 {
264     resetViewportDefaultConfiguration(m_mainFrame.get(), isMobileDoctype);
265 }
266
267 void WebPage::savePageState(HistoryItem& historyItem)
268 {
269     historyItem.setScaleIsInitial(!m_userHasChangedPageScaleFactor);
270     historyItem.setMinimumLayoutSizeInScrollViewCoordinates(m_viewportConfiguration.minimumLayoutSize());
271     historyItem.setContentSize(m_viewportConfiguration.contentsSize());
272 }
273
274 static double scaleAfterViewportWidthChange(double currentScale, bool userHasChangedPageScaleFactor, const ViewportConfiguration& viewportConfiguration, float unobscuredWidthInScrollViewCoordinates, const IntSize& newContentSize, const IntSize& oldContentSize, float visibleHorizontalFraction)
275 {
276     double scale;
277     if (!userHasChangedPageScaleFactor)
278         scale = viewportConfiguration.initialScale();
279     else
280         scale = std::max(std::min(currentScale, viewportConfiguration.maximumScale()), viewportConfiguration.minimumScale());
281
282     LOG(VisibleRects, "scaleAfterViewportWidthChange getting scale %.2f", scale);
283
284     if (userHasChangedPageScaleFactor) {
285         // When the content size changes, we keep the same relative horizontal content width in view, otherwise we would
286         // end up zoomed too far in landscape->portrait, and too close in portrait->landscape.
287         double widthToKeepInView = visibleHorizontalFraction * newContentSize.width();
288         double newScale = unobscuredWidthInScrollViewCoordinates / widthToKeepInView;
289         scale = std::max(std::min(newScale, viewportConfiguration.maximumScale()), viewportConfiguration.minimumScale());
290     }
291     return scale;
292 }
293
294 static FloatPoint relativeCenterAfterContentSizeChange(const FloatRect& originalContentRect, IntSize oldContentSize, IntSize newContentSize)
295 {
296     // If the content size has changed, keep the same relative position.
297     FloatPoint oldContentCenter = originalContentRect.center();
298     float relativeHorizontalPosition = oldContentCenter.x() / oldContentSize.width();
299     float relativeVerticalPosition =  oldContentCenter.y() / oldContentSize.height();
300     return FloatPoint(relativeHorizontalPosition * newContentSize.width(), relativeVerticalPosition * newContentSize.height());
301 }
302
303 static inline FloatRect adjustExposedRectForNewScale(const FloatRect& exposedRect, double exposedRectScale, double newScale)
304 {
305     if (exposedRectScale == newScale)
306         return exposedRect;
307
308     float horizontalChange = exposedRect.width() * exposedRectScale / newScale - exposedRect.width();
309     float verticalChange = exposedRect.height() * exposedRectScale / newScale - exposedRect.height();
310
311     auto adjustedRect = exposedRect;
312     adjustedRect.inflate({ horizontalChange / 2, verticalChange / 2 });
313     return adjustedRect;
314 }
315
316 void WebPage::restorePageState(const HistoryItem& historyItem)
317 {
318     // When a HistoryItem is cleared, its scale factor and scroll point are set to zero. We should not try to restore the other
319     // parameters in those conditions.
320     if (!historyItem.pageScaleFactor()) {
321         send(Messages::WebPageProxy::CouldNotRestorePageState());
322         return;
323     }
324
325     // We can restore the exposed rect and scale, but we cannot touch the scroll position since the obscured insets
326     // may be changing in the UIProcess. The UIProcess can update the position from the information we send and will then
327     // scroll to the correct position through a regular VisibleContentRectUpdate.
328
329     m_userHasChangedPageScaleFactor = !historyItem.scaleIsInitial();
330
331     FrameView& frameView = *m_page->mainFrame().view();
332
333     FloatSize currentMinimumLayoutSizeInScrollViewCoordinates = m_viewportConfiguration.minimumLayoutSize();
334     if (historyItem.minimumLayoutSizeInScrollViewCoordinates() == currentMinimumLayoutSizeInScrollViewCoordinates) {
335         float boundedScale = std::min<float>(m_viewportConfiguration.maximumScale(), std::max<float>(m_viewportConfiguration.minimumScale(), historyItem.pageScaleFactor()));
336         scalePage(boundedScale, IntPoint());
337
338         std::optional<FloatPoint> scrollPosition;
339         if (historyItem.shouldRestoreScrollPosition()) {
340             m_drawingArea->setExposedContentRect(historyItem.exposedContentRect());
341             scrollPosition = FloatPoint(historyItem.scrollPosition());
342         }
343         send(Messages::WebPageProxy::RestorePageState(scrollPosition, frameView.scrollOrigin(), historyItem.obscuredInsets(), boundedScale));
344     } else {
345         IntSize oldContentSize = historyItem.contentSize();
346         IntSize newContentSize = frameView.contentsSize();
347         double visibleHorizontalFraction = static_cast<float>(historyItem.unobscuredContentRect().width()) / oldContentSize.width();
348
349         double newScale = scaleAfterViewportWidthChange(historyItem.pageScaleFactor(), !historyItem.scaleIsInitial(), m_viewportConfiguration, currentMinimumLayoutSizeInScrollViewCoordinates.width(), newContentSize, oldContentSize, visibleHorizontalFraction);
350
351         std::optional<FloatPoint> newCenter;
352         if (historyItem.shouldRestoreScrollPosition()) {
353             if (!oldContentSize.isEmpty() && !newContentSize.isEmpty() && newContentSize != oldContentSize)
354                 newCenter = relativeCenterAfterContentSizeChange(historyItem.unobscuredContentRect(), oldContentSize, newContentSize);
355             else
356                 newCenter = FloatRect(historyItem.unobscuredContentRect()).center();
357         }
358
359         scalePage(newScale, IntPoint());
360         send(Messages::WebPageProxy::RestorePageCenterAndScale(newCenter, newScale));
361     }
362 }
363
364 double WebPage::minimumPageScaleFactor() const
365 {
366     if (!m_viewportConfiguration.allowsUserScaling())
367         return m_page->pageScaleFactor();
368     return m_viewportConfiguration.minimumScale();
369 }
370
371 double WebPage::maximumPageScaleFactor() const
372 {
373     if (!m_viewportConfiguration.allowsUserScaling())
374         return m_page->pageScaleFactor();
375     return m_viewportConfiguration.maximumScale();
376 }
377
378 double WebPage::maximumPageScaleFactorIgnoringAlwaysScalable() const
379 {
380     if (!m_viewportConfiguration.allowsUserScalingIgnoringAlwaysScalable())
381         return m_page->pageScaleFactor();
382     return m_viewportConfiguration.maximumScaleIgnoringAlwaysScalable();
383 }
384
385 bool WebPage::allowsUserScaling() const
386 {
387     return m_viewportConfiguration.allowsUserScaling();
388 }
389
390 bool WebPage::handleEditingKeyboardEvent(KeyboardEvent* event)
391 {
392     auto* platformEvent = event->underlyingPlatformEvent();
393     if (!platformEvent)
394         return false;
395
396     // FIXME: Interpret the event immediately upon receiving it in UI process, without sending to WebProcess first.
397     bool eventWasHandled = false;
398     bool sendResult = WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPageProxy::InterpretKeyEvent(editorState(), platformEvent->type() == PlatformKeyboardEvent::Char),
399         Messages::WebPageProxy::InterpretKeyEvent::Reply(eventWasHandled), m_pageID);
400     return sendResult && eventWasHandled;
401 }
402
403 bool WebPage::parentProcessHasServiceWorkerEntitlement() const
404 {
405     static bool hasEntitlement = WTF::hasEntitlement(WebProcess::singleton().parentProcessConnection()->xpcConnection(), "com.apple.developer.WebKit.ServiceWorkers");
406     return hasEntitlement;
407 }
408
409 void WebPage::sendComplexTextInputToPlugin(uint64_t, const String&)
410 {
411     notImplemented();
412 }
413
414 void WebPage::performDictionaryLookupAtLocation(const FloatPoint&)
415 {
416     notImplemented();
417 }
418
419 void WebPage::performDictionaryLookupForSelection(Frame&, const VisibleSelection&, TextIndicatorPresentationTransition)
420 {
421     notImplemented();
422 }
423
424 void WebPage::performDictionaryLookupForRange(Frame&, Range&, NSDictionary *, TextIndicatorPresentationTransition)
425 {
426     notImplemented();
427 }
428
429 bool WebPage::performNonEditingBehaviorForSelector(const String&, WebCore::KeyboardEvent*)
430 {
431     notImplemented();
432     return false;
433 }
434
435 bool WebPage::performDefaultBehaviorForKeyEvent(const WebKeyboardEvent&)
436 {
437     notImplemented();
438     return false;
439 }
440
441 void WebPage::getSelectionContext(CallbackID callbackID)
442 {
443     Frame& frame = m_page->focusController().focusedOrMainFrame();
444     if (!frame.selection().isRange()) {
445         send(Messages::WebPageProxy::SelectionContextCallback(String(), String(), String(), callbackID));
446         return;
447     }
448     const int selectionExtendedContextLength = 350;
449     
450     String selectedText = plainTextReplacingNoBreakSpace(frame.selection().selection().toNormalizedRange().get());
451     String textBefore = plainTextReplacingNoBreakSpace(rangeExpandedByCharactersInDirectionAtWordBoundary(frame.selection().selection().start(), selectionExtendedContextLength, DirectionBackward).get(), TextIteratorDefaultBehavior, true);
452     String textAfter = plainTextReplacingNoBreakSpace(rangeExpandedByCharactersInDirectionAtWordBoundary(frame.selection().selection().end(), selectionExtendedContextLength, DirectionForward).get(), TextIteratorDefaultBehavior, true);
453
454     send(Messages::WebPageProxy::SelectionContextCallback(selectedText, textBefore, textAfter, callbackID));
455 }
456
457 NSObject *WebPage::accessibilityObjectForMainFramePlugin()
458 {
459     if (!m_page)
460         return nil;
461     
462     if (auto* pluginView = pluginViewForFrame(&m_page->mainFrame()))
463         return pluginView->accessibilityObject();
464     
465     return nil;
466 }
467     
468 void WebPage::registerUIProcessAccessibilityTokens(const IPC::DataReference& elementToken, const IPC::DataReference&)
469 {
470     NSData *elementTokenData = [NSData dataWithBytes:elementToken.data() length:elementToken.size()];
471     [m_mockAccessibilityElement setRemoteTokenData:elementTokenData];
472 }
473
474 void WebPage::readSelectionFromPasteboard(const String&, bool&)
475 {
476     notImplemented();
477 }
478
479 void WebPage::getStringSelectionForPasteboard(String&)
480 {
481     notImplemented();
482 }
483
484 void WebPage::getDataSelectionForPasteboard(const String, SharedMemory::Handle&, uint64_t&)
485 {
486     notImplemented();
487 }
488
489 WKAccessibilityWebPageObject* WebPage::accessibilityRemoteObject()
490 {
491     notImplemented();
492     return 0;
493 }
494
495 bool WebPage::platformCanHandleRequest(const WebCore::ResourceRequest&)
496 {
497     notImplemented();
498     return false;
499 }
500
501 void WebPage::shouldDelayWindowOrderingEvent(const WebKit::WebMouseEvent&, bool&)
502 {
503     notImplemented();
504 }
505
506 void WebPage::acceptsFirstMouse(int, const WebKit::WebMouseEvent&, bool&)
507 {
508     notImplemented();
509 }
510
511 void WebPage::computePagesForPrintingPDFDocument(uint64_t, const PrintInfo&, Vector<IntRect>&)
512 {
513     notImplemented();
514 }
515
516 void WebPage::drawPagesToPDFFromPDFDocument(CGContextRef, PDFDocument *, const PrintInfo&, uint32_t, uint32_t)
517 {
518     notImplemented();
519 }
520
521 void WebPage::advanceToNextMisspelling(bool)
522 {
523     notImplemented();
524 }
525
526 IntRect WebPage::rectForElementAtInteractionLocation()
527 {
528     HitTestResult result = m_page->mainFrame().eventHandler().hitTestResultAtPoint(m_lastInteractionLocation, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::AllowChildFrameContent);
529     Node* hitNode = result.innerNode();
530     if (!hitNode || !hitNode->renderer())
531         return IntRect();
532     return result.innerNodeFrame()->view()->contentsToRootView(hitNode->renderer()->absoluteBoundingBoxRect(true));
533 }
534
535 void WebPage::updateSelectionAppearance()
536 {
537     Frame& frame = m_page->focusController().focusedOrMainFrame();
538     if (!frame.editor().ignoreSelectionChanges() && (frame.editor().hasComposition() || !frame.selection().selection().isNone()))
539         didChangeSelection();
540 }
541
542 void WebPage::handleSyntheticClick(Node* nodeRespondingToClick, const WebCore::FloatPoint& location)
543 {
544     IntPoint roundedAdjustedPoint = roundedIntPoint(location);
545     Frame& mainframe = m_page->mainFrame();
546
547     WKBeginObservingContentChanges(true);
548
549     mainframe.eventHandler().mouseMoved(PlatformMouseEvent(roundedAdjustedPoint, roundedAdjustedPoint, NoButton, PlatformEvent::MouseMoved, 0, false, false, false, false, WallTime::now(), WebCore::ForceAtClick, WebCore::NoTap));
550     mainframe.document()->updateStyleIfNeeded();
551
552     WKStopObservingContentChanges();
553
554     m_pendingSyntheticClickNode = nullptr;
555     m_pendingSyntheticClickLocation = FloatPoint();
556
557     if (m_isClosed)
558         return;
559
560     switch (WKObservedContentChange()) {
561     case WKContentVisibilityChange:
562         // The move event caused new contents to appear. Don't send the click event.
563         return;
564     case WKContentIndeterminateChange:
565         // Wait for callback to completePendingSyntheticClickForContentChangeObserver() to decide whether to send the click event.
566         m_pendingSyntheticClickNode = nodeRespondingToClick;
567         m_pendingSyntheticClickLocation = location;
568         return;
569     case WKContentNoChange:
570         completeSyntheticClick(nodeRespondingToClick, location, WebCore::OneFingerTap);
571         return;
572     }
573     ASSERT_NOT_REACHED();
574 }
575
576 void WebPage::completePendingSyntheticClickForContentChangeObserver()
577 {
578     if (!m_pendingSyntheticClickNode)
579         return;
580     // Only dispatch the click if the document didn't get changed by any timers started by the move event.
581     if (WKObservedContentChange() == WKContentNoChange)
582         completeSyntheticClick(m_pendingSyntheticClickNode.get(), m_pendingSyntheticClickLocation, WebCore::OneFingerTap);
583
584     m_pendingSyntheticClickNode = nullptr;
585     m_pendingSyntheticClickLocation = FloatPoint();
586 }
587
588 void WebPage::completeSyntheticClick(Node* nodeRespondingToClick, const WebCore::FloatPoint& location, SyntheticClickType syntheticClickType)
589 {
590     IntPoint roundedAdjustedPoint = roundedIntPoint(location);
591     Frame& mainframe = m_page->mainFrame();
592
593     RefPtr<Frame> oldFocusedFrame = m_page->focusController().focusedFrame();
594     RefPtr<Element> oldFocusedElement = oldFocusedFrame ? oldFocusedFrame->document()->focusedElement() : nullptr;
595
596     SetForScope<bool> userIsInteractingChange { m_userIsInteracting, true };
597
598     bool tapWasHandled = false;
599     m_lastInteractionLocation = roundedAdjustedPoint;
600
601     tapWasHandled |= mainframe.eventHandler().handleMousePressEvent(PlatformMouseEvent(roundedAdjustedPoint, roundedAdjustedPoint, LeftButton, PlatformEvent::MousePressed, 1, false, false, false, false, WallTime::now(), WebCore::ForceAtClick, syntheticClickType));
602     if (m_isClosed)
603         return;
604
605     tapWasHandled |= mainframe.eventHandler().handleMouseReleaseEvent(PlatformMouseEvent(roundedAdjustedPoint, roundedAdjustedPoint, LeftButton, PlatformEvent::MouseReleased, 1, false, false, false, false, WallTime::now(), WebCore::ForceAtClick, syntheticClickType));
606     if (m_isClosed)
607         return;
608
609     RefPtr<Frame> newFocusedFrame = m_page->focusController().focusedFrame();
610     RefPtr<Element> newFocusedElement = newFocusedFrame ? newFocusedFrame->document()->focusedElement() : nullptr;
611
612     // If the focus has not changed, we need to notify the client anyway, since it might be
613     // necessary to start assisting the node.
614     // If the node has been focused by JavaScript without user interaction, the
615     // keyboard is not on screen.
616     if (newFocusedElement && newFocusedElement == oldFocusedElement)
617         elementDidFocus(newFocusedElement.get());
618
619     if (!tapWasHandled || !nodeRespondingToClick || !nodeRespondingToClick->isElementNode())
620         send(Messages::WebPageProxy::DidNotHandleTapAsClick(roundedIntPoint(location)));
621     
622     send(Messages::WebPageProxy::DidCompleteSyntheticClick());
623 }
624
625 void WebPage::handleTap(const IntPoint& point, uint64_t lastLayerTreeTransactionId)
626 {
627     FloatPoint adjustedPoint;
628     Node* nodeRespondingToClick = m_page->mainFrame().nodeRespondingToClickEvents(point, adjustedPoint);
629     Frame* frameRespondingToClick = nodeRespondingToClick ? nodeRespondingToClick->document().frame() : nullptr;
630     IntPoint adjustedIntPoint = roundedIntPoint(adjustedPoint);
631
632     if (!frameRespondingToClick || lastLayerTreeTransactionId < WebFrame::fromCoreFrame(*frameRespondingToClick)->firstLayerTreeTransactionIDAfterDidCommitLoad())
633         send(Messages::WebPageProxy::DidNotHandleTapAsClick(adjustedIntPoint));
634 #if ENABLE(DATA_DETECTION)
635     else if (is<Element>(*nodeRespondingToClick) && DataDetection::shouldCancelDefaultAction(downcast<Element>(*nodeRespondingToClick))) {
636         InteractionInformationRequest request(adjustedIntPoint);
637         requestPositionInformation(request);
638         send(Messages::WebPageProxy::DidNotHandleTapAsClick(adjustedIntPoint));
639     }
640 #endif
641     else
642         handleSyntheticClick(nodeRespondingToClick, adjustedPoint);
643 }
644
645 void WebPage::requestAssistedNodeInformation(WebKit::CallbackID callbackID)
646 {
647     AssistedNodeInformation info;
648     if (m_assistedNode)
649         getAssistedNodeInformation(info);
650
651     send(Messages::WebPageProxy::AssistedNodeInformationCallback(info, callbackID));
652 }
653
654 #if ENABLE(DATA_INTERACTION)
655 void WebPage::requestStartDataInteraction(const IntPoint& clientPosition, const IntPoint& globalPosition)
656 {
657     bool didStart = m_page->mainFrame().eventHandler().tryToBeginDataInteractionAtPoint(clientPosition, globalPosition);
658     send(Messages::WebPageProxy::DidHandleStartDataInteractionRequest(didStart));
659 }
660
661 void WebPage::requestAdditionalItemsForDragSession(const IntPoint& clientPosition, const IntPoint& globalPosition)
662 {
663     // 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.
664     // This process is opaque to the UI process, which still maintains the old drag item in its drag session. Similarly, this persistent drag session
665     // is opaque to the web process, which only sees that the current drag has ended, and that a new one is beginning.
666     PlatformMouseEvent event(clientPosition, globalPosition, LeftButton, PlatformEvent::MouseMoved, 0, false, false, false, false, WallTime::now(), 0, NoTap);
667     m_page->dragController().dragEnded();
668     m_page->mainFrame().eventHandler().dragSourceEndedAt(event, DragOperationNone, MayExtendDragSession::Yes);
669
670     bool didHandleDrag = m_page->mainFrame().eventHandler().tryToBeginDataInteractionAtPoint(clientPosition, globalPosition);
671     send(Messages::WebPageProxy::DidHandleAdditionalDragItemsRequest(didHandleDrag));
672 }
673
674 void WebPage::didConcludeEditDataInteraction()
675 {
676     std::optional<TextIndicatorData> textIndicatorData;
677
678     static auto defaultEditDataInteractionTextIndicatorOptions = TextIndicatorOptionIncludeSnapshotOfAllVisibleContentWithoutSelection | TextIndicatorOptionExpandClipBeyondVisibleRect | TextIndicatorOptionPaintAllContent | TextIndicatorOptionIncludeMarginIfRangeMatchesSelection | TextIndicatorOptionPaintBackgrounds | TextIndicatorOptionComputeEstimatedBackgroundColor| TextIndicatorOptionUseSelectionRectForSizing | TextIndicatorOptionIncludeSnapshotWithSelectionHighlight;
679     auto& frame = m_page->focusController().focusedOrMainFrame();
680     if (auto range = frame.selection().selection().toNormalizedRange()) {
681         if (auto textIndicator = TextIndicator::createWithRange(*range, defaultEditDataInteractionTextIndicatorOptions, TextIndicatorPresentationTransition::None, FloatSize()))
682             textIndicatorData = textIndicator->data();
683     }
684
685     send(Messages::WebPageProxy::DidConcludeEditDataInteraction(textIndicatorData));
686 }
687 #endif
688
689 void WebPage::sendTapHighlightForNodeIfNecessary(uint64_t requestID, Node* node)
690 {
691 #if ENABLE(TOUCH_EVENTS)
692     if (!node)
693         return;
694
695     if (m_page->isEditable() && node == m_page->mainFrame().document()->body())
696         return;
697
698     if (is<Element>(*node)) {
699         ASSERT(m_page);
700         m_page->mainFrame().loader().client().prefetchDNS(downcast<Element>(*node).absoluteLinkURL().host().toString());
701     }
702
703     if (is<HTMLAreaElement>(node)) {
704         node = downcast<HTMLAreaElement>(node)->imageElement();
705         if (!node)
706             return;
707     }
708
709     Vector<FloatQuad> quads;
710     if (RenderObject *renderer = node->renderer()) {
711         renderer->absoluteQuads(quads);
712         Color highlightColor = renderer->style().tapHighlightColor();
713         if (!node->document().frame()->isMainFrame()) {
714             FrameView* view = node->document().frame()->view();
715             for (size_t i = 0; i < quads.size(); ++i) {
716                 FloatQuad& currentQuad = quads[i];
717                 currentQuad.setP1(view->contentsToRootView(roundedIntPoint(currentQuad.p1())));
718                 currentQuad.setP2(view->contentsToRootView(roundedIntPoint(currentQuad.p2())));
719                 currentQuad.setP3(view->contentsToRootView(roundedIntPoint(currentQuad.p3())));
720                 currentQuad.setP4(view->contentsToRootView(roundedIntPoint(currentQuad.p4())));
721             }
722         }
723
724         RoundedRect::Radii borderRadii;
725         if (is<RenderBox>(*renderer))
726             borderRadii = downcast<RenderBox>(*renderer).borderRadii();
727
728         send(Messages::WebPageProxy::DidGetTapHighlightGeometries(requestID, highlightColor, quads, roundedIntSize(borderRadii.topLeft()), roundedIntSize(borderRadii.topRight()), roundedIntSize(borderRadii.bottomLeft()), roundedIntSize(borderRadii.bottomRight())));
729     }
730 #else
731     UNUSED_PARAM(requestID);
732     UNUSED_PARAM(node);
733 #endif
734 }
735
736 void WebPage::handleTwoFingerTapAtPoint(const WebCore::IntPoint& point, uint64_t requestID)
737 {
738     FloatPoint adjustedPoint;
739     Node* nodeRespondingToClick = m_page->mainFrame().nodeRespondingToClickEvents(point, adjustedPoint);
740     if (!nodeRespondingToClick || !nodeRespondingToClick->renderer()) {
741         send(Messages::WebPageProxy::DidNotHandleTapAsClick(roundedIntPoint(adjustedPoint)));
742         return;
743     }
744     sendTapHighlightForNodeIfNecessary(requestID, nodeRespondingToClick);
745 #if ENABLE(DATA_DETECTION)
746     if (is<Element>(*nodeRespondingToClick) && DataDetection::shouldCancelDefaultAction(downcast<Element>(*nodeRespondingToClick))) {
747         InteractionInformationRequest request(roundedIntPoint(adjustedPoint));
748         requestPositionInformation(request);
749         send(Messages::WebPageProxy::DidNotHandleTapAsClick(roundedIntPoint(adjustedPoint)));
750     } else
751 #endif
752         completeSyntheticClick(nodeRespondingToClick, adjustedPoint, WebCore::TwoFingerTap);
753 }
754
755 void WebPage::potentialTapAtPosition(uint64_t requestID, const WebCore::FloatPoint& position)
756 {
757     m_potentialTapNode = m_page->mainFrame().nodeRespondingToClickEvents(position, m_potentialTapLocation, m_potentialTapSecurityOrigin.get());
758     sendTapHighlightForNodeIfNecessary(requestID, m_potentialTapNode.get());
759 #if ENABLE(TOUCH_EVENTS)
760     if (m_potentialTapNode && !m_potentialTapNode->allowsDoubleTapGesture())
761         send(Messages::WebPageProxy::DisableDoubleTapGesturesDuringTapIfNecessary(requestID));
762 #endif
763 }
764
765 void WebPage::commitPotentialTap(uint64_t lastLayerTreeTransactionId)
766 {
767     if (!m_potentialTapNode || (!m_potentialTapNode->renderer() && !is<HTMLAreaElement>(m_potentialTapNode.get()))) {
768         commitPotentialTapFailed();
769         return;
770     }
771
772     FloatPoint adjustedPoint;
773     Node* nodeRespondingToClick = m_page->mainFrame().nodeRespondingToClickEvents(m_potentialTapLocation, adjustedPoint, m_potentialTapSecurityOrigin.get());
774     Frame* frameRespondingToClick = nodeRespondingToClick ? nodeRespondingToClick->document().frame() : nullptr;
775
776     if (!frameRespondingToClick || lastLayerTreeTransactionId < WebFrame::fromCoreFrame(*frameRespondingToClick)->firstLayerTreeTransactionIDAfterDidCommitLoad()) {
777         commitPotentialTapFailed();
778         return;
779     }
780
781     if (m_potentialTapNode == nodeRespondingToClick) {
782 #if ENABLE(DATA_DETECTION)
783         if (is<Element>(*nodeRespondingToClick) && DataDetection::shouldCancelDefaultAction(downcast<Element>(*nodeRespondingToClick))) {
784             InteractionInformationRequest request(roundedIntPoint(m_potentialTapLocation));
785             requestPositionInformation(request);
786             commitPotentialTapFailed();
787         } else
788 #endif
789             handleSyntheticClick(nodeRespondingToClick, adjustedPoint);
790     } else
791         commitPotentialTapFailed();
792
793     m_potentialTapNode = nullptr;
794     m_potentialTapLocation = FloatPoint();
795     m_potentialTapSecurityOrigin = nullptr;
796 }
797
798 void WebPage::commitPotentialTapFailed()
799 {
800     send(Messages::WebPageProxy::CommitPotentialTapFailed());
801     send(Messages::WebPageProxy::DidNotHandleTapAsClick(roundedIntPoint(m_potentialTapLocation)));
802 }
803
804 void WebPage::cancelPotentialTap()
805 {
806     cancelPotentialTapInFrame(*m_mainFrame);
807 }
808
809 void WebPage::cancelPotentialTapInFrame(WebFrame& frame)
810 {
811     if (m_potentialTapNode) {
812         Frame* potentialTapFrame = m_potentialTapNode->document().frame();
813         if (potentialTapFrame && !potentialTapFrame->tree().isDescendantOf(frame.coreFrame()))
814             return;
815     }
816
817     m_potentialTapNode = nullptr;
818     m_potentialTapLocation = FloatPoint();
819     m_potentialTapSecurityOrigin = nullptr;
820 }
821
822 void WebPage::tapHighlightAtPosition(uint64_t requestID, const FloatPoint& position)
823 {
824     Frame& mainframe = m_page->mainFrame();
825     FloatPoint adjustedPoint;
826     sendTapHighlightForNodeIfNecessary(requestID, mainframe.nodeRespondingToClickEvents(position, adjustedPoint));
827 }
828
829 void WebPage::inspectorNodeSearchMovedToPosition(const FloatPoint& position)
830 {
831     IntPoint adjustedPoint = roundedIntPoint(position);
832     Frame& mainframe = m_page->mainFrame();
833
834     mainframe.eventHandler().mouseMoved(PlatformMouseEvent(adjustedPoint, adjustedPoint, NoButton, PlatformEvent::MouseMoved, 0, false, false, false, false, { }, 0, WebCore::NoTap));
835     mainframe.document()->updateStyleIfNeeded();
836 }
837
838 void WebPage::inspectorNodeSearchEndedAtPosition(const FloatPoint& position)
839 {
840     if (Node* node = m_page->mainFrame().deepestNodeAtLocation(position))
841         node->inspect();
842 }
843
844 void WebPage::blurAssistedNode()
845 {
846     if (is<Element>(m_assistedNode.get()))
847         downcast<Element>(*m_assistedNode).blur();
848 }
849
850 void WebPage::setAssistedNodeValue(const String& value)
851 {
852     // FIXME: should also handle the case of HTMLSelectElement.
853     if (is<HTMLInputElement>(m_assistedNode.get()))
854         downcast<HTMLInputElement>(*m_assistedNode).setValue(value, DispatchInputAndChangeEvent);
855 }
856
857 void WebPage::setAssistedNodeValueAsNumber(double value)
858 {
859     if (is<HTMLInputElement>(m_assistedNode.get()))
860         downcast<HTMLInputElement>(*m_assistedNode).setValueAsNumber(value, DispatchInputAndChangeEvent);
861 }
862
863 void WebPage::setAssistedNodeSelectedIndex(uint32_t index, bool allowMultipleSelection)
864 {
865     if (is<HTMLSelectElement>(m_assistedNode.get()))
866         downcast<HTMLSelectElement>(*m_assistedNode).optionSelectedByUser(index, true, allowMultipleSelection);
867 }
868
869 void WebPage::showInspectorHighlight(const WebCore::Highlight& highlight)
870 {
871     send(Messages::WebPageProxy::ShowInspectorHighlight(highlight));
872 }
873
874 void WebPage::hideInspectorHighlight()
875 {
876     send(Messages::WebPageProxy::HideInspectorHighlight());
877 }
878
879 void WebPage::showInspectorIndication()
880 {
881     send(Messages::WebPageProxy::ShowInspectorIndication());
882 }
883
884 void WebPage::hideInspectorIndication()
885 {
886     send(Messages::WebPageProxy::HideInspectorIndication());
887 }
888
889 void WebPage::enableInspectorNodeSearch()
890 {
891     send(Messages::WebPageProxy::EnableInspectorNodeSearch());
892 }
893
894 void WebPage::disableInspectorNodeSearch()
895 {
896     send(Messages::WebPageProxy::DisableInspectorNodeSearch());
897 }
898
899 void WebPage::setForceAlwaysUserScalable(bool userScalable)
900 {
901     m_forceAlwaysUserScalable = userScalable;
902     m_viewportConfiguration.setForceAlwaysUserScalable(userScalable);
903 }
904
905 static FloatQuad innerFrameQuad(const Frame& frame, const Node& assistedNode)
906 {
907     frame.document()->updateLayoutIgnorePendingStylesheets();
908     RenderElement* renderer = nullptr;
909     if (assistedNode.hasTagName(HTMLNames::textareaTag) || assistedNode.hasTagName(HTMLNames::inputTag) || assistedNode.hasTagName(HTMLNames::selectTag))
910         renderer = downcast<RenderElement>(assistedNode.renderer());
911     else if (Element* rootEditableElement = assistedNode.rootEditableElement())
912         renderer = rootEditableElement->renderer();
913     
914     if (!renderer)
915         return FloatQuad();
916
917     auto& style = renderer->style();
918     IntRect boundingBox = renderer->absoluteBoundingBoxRect(true /* use transforms*/);
919
920     boundingBox.move(style.borderLeftWidth(), style.borderTopWidth());
921     boundingBox.setWidth(boundingBox.width() - style.borderLeftWidth() - style.borderRightWidth());
922     boundingBox.setHeight(boundingBox.height() - style.borderBottomWidth() - style.borderTopWidth());
923
924     return FloatQuad(boundingBox);
925 }
926
927 static IntPoint constrainPoint(const IntPoint& point, const Frame& frame, const Node& assistedNode)
928 {
929     ASSERT(&assistedNode.document() == frame.document());
930     const int DEFAULT_CONSTRAIN_INSET = 2;
931     IntRect innerFrame = innerFrameQuad(frame, assistedNode).enclosingBoundingBox();
932     IntPoint constrainedPoint = point;
933
934     int minX = innerFrame.x() + DEFAULT_CONSTRAIN_INSET;
935     int maxX = innerFrame.maxX() - DEFAULT_CONSTRAIN_INSET;
936     int minY = innerFrame.y() + DEFAULT_CONSTRAIN_INSET;
937     int maxY = innerFrame.maxY() - DEFAULT_CONSTRAIN_INSET;
938
939     if (point.x() < minX)
940         constrainedPoint.setX(minX);
941     else if (point.x() > maxX)
942         constrainedPoint.setX(maxX);
943
944     if (point.y() < minY)
945         constrainedPoint.setY(minY);
946     else if (point.y() >= maxY)
947         constrainedPoint.setY(maxY);
948                     
949     return constrainedPoint;
950 }
951
952 static IntRect selectionBoxForRange(WebCore::Range* range)
953 {
954     if (!range)
955         return IntRect();
956     
957     IntRect boundingRect;
958     Vector<SelectionRect> selectionRects;
959     range->collectSelectionRects(selectionRects);
960     unsigned size = selectionRects.size();
961     
962     for (unsigned i = 0; i < size; ++i) {
963         const IntRect &coreRect = selectionRects[i].rect();
964         if (!i)
965             boundingRect = coreRect;
966         else
967             boundingRect.unite(coreRect);
968     }
969     return boundingRect;
970 }
971
972 static bool canShrinkToTextSelection(Node* node)
973 {
974     if (node && !is<Element>(*node))
975         node = node->parentElement();
976     
977     auto* renderer = (node) ? node->renderer() : nullptr;
978     return renderer && renderer->childrenInline() && (is<RenderBlock>(*renderer) && !downcast<RenderBlock>(*renderer).inlineContinuation()) && !renderer->isTable();
979 }
980
981 static bool hasCustomLineHeight(Node& node)
982 {
983     auto* renderer = node.renderer();
984     return renderer && renderer->style().lineHeight().isSpecified();
985 }
986     
987 RefPtr<Range> WebPage::rangeForWebSelectionAtPosition(const IntPoint& point, const VisiblePosition& position, SelectionFlags& flags)
988 {
989     HitTestResult result = m_page->mainFrame().eventHandler().hitTestResultAtPoint((point), HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowUserAgentShadowContent | HitTestRequest::AllowChildFrameContent);
990
991     Node* currentNode = result.innerNode();
992     if (!currentNode)
993         return nullptr;
994     RefPtr<Range> range;
995     FloatRect boundingRectInScrollViewCoordinates;
996
997     if (!currentNode->isTextNode() && !canShrinkToTextSelection(currentNode) && hasCustomLineHeight(*currentNode)) {
998         auto* renderer = currentNode->renderer();
999         if (is<RenderBlockFlow>(renderer)) {
1000             auto* renderText = downcast<RenderBlockFlow>(*renderer).findClosestTextAtAbsolutePoint(point);
1001             if (renderText && renderText->textNode())
1002                 currentNode = renderText->textNode();
1003         }
1004     }
1005
1006     if (currentNode->isTextNode()) {
1007         range = enclosingTextUnitOfGranularity(position, ParagraphGranularity, DirectionForward);
1008         if (!range || range->collapsed())
1009             range = Range::create(currentNode->document(), position, position);
1010         else {
1011             m_blockRectForTextSelection = selectionBoxForRange(range.get());
1012             range = wordRangeFromPosition(position);
1013         }
1014
1015         return range;
1016     }
1017
1018     if (!currentNode->isElementNode())
1019         currentNode = currentNode->parentElement();
1020
1021     Node* bestChoice = currentNode;
1022     while (currentNode) {
1023         if (currentNode->renderer()) {
1024             boundingRectInScrollViewCoordinates = currentNode->renderer()->absoluteBoundingBoxRect(true);
1025             boundingRectInScrollViewCoordinates.scale(m_page->pageScaleFactor());
1026             if (boundingRectInScrollViewCoordinates.width() > m_blockSelectionDesiredSize.width() && boundingRectInScrollViewCoordinates.height() > m_blockSelectionDesiredSize.height())
1027                 break;
1028             bestChoice = currentNode;
1029         }
1030         currentNode = currentNode->parentElement();
1031     }
1032
1033     if (!bestChoice)
1034         return nullptr;
1035
1036     RenderObject* renderer = bestChoice->renderer();
1037     if (!renderer || renderer->style().userSelect() == UserSelect::None)
1038         return nullptr;
1039
1040     if (renderer->childrenInline() && (is<RenderBlock>(*renderer) && !downcast<RenderBlock>(*renderer).inlineContinuation()) && !renderer->isTable()) {
1041         range = enclosingTextUnitOfGranularity(position, WordGranularity, DirectionBackward);
1042         if (range && !range->collapsed())
1043             return range;
1044     }
1045
1046     // If all we could find is a block whose height is very close to the height
1047     // of the visible area, don't use it.
1048     const float adjustmentFactor = .97;
1049     boundingRectInScrollViewCoordinates = renderer->absoluteBoundingBoxRect(true);
1050
1051     if (boundingRectInScrollViewCoordinates.height() > m_page->mainFrame().view()->exposedContentRect().height() * adjustmentFactor)
1052         return nullptr;
1053
1054     range = Range::create(bestChoice->document());
1055     range->selectNodeContents(*bestChoice);
1056     return range->collapsed() ? nullptr : range;
1057 }
1058
1059 void WebPage::selectWithGesture(const IntPoint& point, uint32_t granularity, uint32_t gestureType, uint32_t gestureState, bool isInteractingWithAssistedNode, CallbackID callbackID)
1060 {
1061     auto& frame = m_page->focusController().focusedOrMainFrame();
1062     VisiblePosition position = visiblePositionInFocusedNodeForPoint(frame, point, isInteractingWithAssistedNode);
1063
1064     if (position.isNull()) {
1065         send(Messages::WebPageProxy::GestureCallback(point, gestureType, gestureState, 0, callbackID));
1066         return;
1067     }
1068     RefPtr<Range> range;
1069     SelectionFlags flags = None;
1070     GestureRecognizerState wkGestureState = static_cast<GestureRecognizerState>(gestureState);
1071     switch (static_cast<GestureType>(gestureType)) {
1072     case GestureType::PhraseBoundary:
1073     {
1074         if (!frame.editor().hasComposition())
1075             break;
1076         RefPtr<Range> markedRange = frame.editor().compositionRange();
1077         if (position < markedRange->startPosition())
1078             position = markedRange->startPosition();
1079         if (position > markedRange->endPosition())
1080             position = markedRange->endPosition();
1081         if (wkGestureState != GestureRecognizerState::Began)
1082             flags = distanceBetweenPositions(markedRange->startPosition(), frame.selection().selection().start()) != distanceBetweenPositions(markedRange->startPosition(), position) ? PhraseBoundaryChanged : None;
1083         else
1084             flags = PhraseBoundaryChanged;
1085         range = Range::create(*frame.document(), position, position);
1086     }
1087         break;
1088
1089     case GestureType::OneFingerTap:
1090     {
1091         VisiblePosition result;
1092         // move the position at the end of the word
1093         if (atBoundaryOfGranularity(position, LineGranularity, DirectionForward)) {
1094             // Don't cross line boundaries.
1095             result = position;
1096         } else if (withinTextUnitOfGranularity(position, WordGranularity, DirectionForward)) {
1097             // The position lies within a word.
1098             RefPtr<Range> wordRange = enclosingTextUnitOfGranularity(position, WordGranularity, DirectionForward);
1099             if (wordRange) {
1100                 result = wordRange->startPosition();
1101                 if (distanceBetweenPositions(position, result) > 1)
1102                     result = wordRange->endPosition();
1103             }
1104         } else if (atBoundaryOfGranularity(position, WordGranularity, DirectionBackward)) {
1105             // The position is at the end of a word.
1106             result = position;
1107         } else {
1108             // The position is not within a word.
1109             // Go to the next boundary.
1110             result = positionOfNextBoundaryOfGranularity(position, WordGranularity, DirectionForward);
1111
1112             // If there is no such boundary we go to the end of the element.
1113             if (result.isNull())
1114                 result = endOfEditableContent(position);
1115         }
1116         if (result.isNotNull())
1117             range = Range::create(*frame.document(), result, result);
1118     }
1119         break;
1120
1121     case GestureType::Loupe:
1122         if (position.rootEditableElement())
1123             range = Range::create(*frame.document(), position, position);
1124         else
1125 #if !PLATFORM(IOSMAC)
1126             range = wordRangeFromPosition(position);
1127 #else
1128             switch (wkGestureState) {
1129             case GestureRecognizerState::Began:
1130                 m_startingGestureRange = Range::create(*frame.document(), position, position);
1131                 break;
1132             case GestureRecognizerState::Changed:
1133                 if (m_startingGestureRange) {
1134                     if (m_startingGestureRange->startPosition() < position)
1135                         range = Range::create(*frame.document(), m_startingGestureRange->startPosition(), position);
1136                     else
1137                         range = Range::create(*frame.document(), position, m_startingGestureRange->startPosition());
1138                 }
1139                 break;
1140             case GestureRecognizerState::Ended:
1141             case GestureRecognizerState::Cancelled:
1142                 m_startingGestureRange = nullptr;
1143                 break;
1144             case GestureRecognizerState::Failed:
1145             case GestureRecognizerState::Possible:
1146                 ASSERT_NOT_REACHED();
1147                 break;
1148             }
1149 #endif
1150         break;
1151
1152     case GestureType::TapAndAHalf:
1153         switch (wkGestureState) {
1154         case GestureRecognizerState::Began:
1155             range = wordRangeFromPosition(position);
1156             m_currentWordRange = range ? RefPtr<Range>(Range::create(*frame.document(), range->startPosition(), range->endPosition())) : nullptr;
1157             break;
1158         case GestureRecognizerState::Changed:
1159             if (!m_currentWordRange)
1160                 break;
1161             range = Range::create(*frame.document(), m_currentWordRange->startPosition(), m_currentWordRange->endPosition());
1162             if (position < range->startPosition())
1163                 range->setStart(position.deepEquivalent());
1164             if (position > range->endPosition())
1165                 range->setEnd(position.deepEquivalent());
1166             break;
1167         case GestureRecognizerState::Ended:
1168         case GestureRecognizerState::Cancelled:
1169             m_currentWordRange = nullptr;
1170             break;
1171         case GestureRecognizerState::Failed:
1172         case GestureRecognizerState::Possible:
1173             ASSERT_NOT_REACHED();
1174         }
1175         break;
1176
1177     case GestureType::OneFingerDoubleTap:
1178         if (atBoundaryOfGranularity(position, LineGranularity, DirectionForward)) {
1179             // Double-tap at end of line only places insertion point there.
1180             // This helps to get the callout for pasting at ends of lines,
1181             // paragraphs, and documents.
1182             range = Range::create(*frame.document(), position, position);
1183          } else
1184             range = wordRangeFromPosition(position);
1185         break;
1186
1187     case GestureType::TwoFingerSingleTap:
1188         // Single tap with two fingers selects the entire paragraph.
1189         range = enclosingTextUnitOfGranularity(position, ParagraphGranularity, DirectionForward);
1190         break;
1191
1192     case GestureType::OneFingerTripleTap:
1193         if (atBoundaryOfGranularity(position, LineGranularity, DirectionForward)) {
1194             // Triple-tap at end of line only places insertion point there.
1195             // This helps to get the callout for pasting at ends of lines,
1196             // paragraphs, and documents.
1197             range = Range::create(*frame.document(), position, position);
1198         } else
1199             range = enclosingTextUnitOfGranularity(position, ParagraphGranularity, DirectionForward);
1200         break;
1201
1202     case GestureType::MakeWebSelection:
1203         if (wkGestureState == GestureRecognizerState::Began) {
1204             m_blockSelectionDesiredSize.setWidth(blockSelectionStartWidth);
1205             m_blockSelectionDesiredSize.setHeight(blockSelectionStartHeight);
1206             m_currentBlockSelection = nullptr;
1207         }
1208         range = rangeForWebSelectionAtPosition(point, position, flags);
1209         break;
1210
1211     default:
1212         break;
1213     }
1214     if (range)
1215         frame.selection().setSelectedRange(range.get(), position.affinity(), true, UserTriggered);
1216
1217     send(Messages::WebPageProxy::GestureCallback(point, gestureType, gestureState, static_cast<uint32_t>(flags), callbackID));
1218 }
1219
1220 static RefPtr<Range> rangeForPointInRootViewCoordinates(Frame& frame, const IntPoint& pointInRootViewCoordinates, bool baseIsStart)
1221 {
1222     VisibleSelection existingSelection = frame.selection().selection();
1223     VisiblePosition selectionStart = existingSelection.visibleStart();
1224     VisiblePosition selectionEnd = existingSelection.visibleEnd();
1225
1226     auto pointInDocument = frame.view()->rootViewToContents(pointInRootViewCoordinates);
1227
1228     if (baseIsStart) {
1229         int startY = selectionStart.absoluteCaretBounds().center().y();
1230         if (pointInDocument.y() < startY)
1231             pointInDocument.setY(startY);
1232     } else {
1233         int endY = selectionEnd.absoluteCaretBounds().center().y();
1234         if (pointInDocument.y() > endY)
1235             pointInDocument.setY(endY);
1236     }
1237     
1238     VisiblePosition result;
1239     RefPtr<Range> range;
1240     
1241     HitTestResult hitTest = frame.eventHandler().hitTestResultAtPoint(pointInDocument, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::AllowChildFrameContent);
1242     if (hitTest.targetNode())
1243         result = frame.eventHandler().selectionExtentRespectingEditingBoundary(frame.selection().selection(), hitTest.localPoint(), hitTest.targetNode()).deepEquivalent();
1244     else
1245         result = frame.visiblePositionForPoint(pointInDocument).deepEquivalent();
1246     
1247     if (baseIsStart) {
1248         if (comparePositions(result, selectionStart) <= 0)
1249             result = selectionStart.next();
1250         else if (&selectionStart.deepEquivalent().anchorNode()->treeScope() != &hitTest.targetNode()->treeScope())
1251             result = VisibleSelection::adjustPositionForEnd(result.deepEquivalent(), selectionStart.deepEquivalent().containerNode());
1252         
1253         if (result.isNotNull())
1254             range = Range::create(*frame.document(), selectionStart, result);
1255     } else {
1256         if (comparePositions(selectionEnd, result) <= 0)
1257             result = selectionEnd.previous();
1258         else if (&hitTest.targetNode()->treeScope() != &selectionEnd.deepEquivalent().anchorNode()->treeScope())
1259             result = VisibleSelection::adjustPositionForStart(result.deepEquivalent(), selectionEnd.deepEquivalent().containerNode());
1260         
1261         if (result.isNotNull())
1262             range = Range::create(*frame.document(), result.deepEquivalent(), selectionEnd);
1263     }
1264     
1265     return range;
1266 }
1267
1268 static RefPtr<Range> rangeAtWordBoundaryForPosition(Frame* frame, const VisiblePosition& position, bool baseIsStart, SelectionDirection direction)
1269 {
1270     SelectionDirection sameDirection = baseIsStart ? DirectionForward : DirectionBackward;
1271     SelectionDirection oppositeDirection = baseIsStart ? DirectionBackward : DirectionForward;
1272     VisiblePosition base = baseIsStart ? frame->selection().selection().visibleStart() : frame->selection().selection().visibleEnd();
1273     VisiblePosition extent = baseIsStart ? frame->selection().selection().visibleEnd() : frame->selection().selection().visibleStart();
1274     VisiblePosition initialExtent = position;
1275
1276     if (atBoundaryOfGranularity(extent, WordGranularity, sameDirection)) {
1277         // This is a word boundary. Leave selection where it is.
1278         return nullptr;
1279     }
1280
1281     if (atBoundaryOfGranularity(extent, WordGranularity, oppositeDirection)) {
1282         // This is a word boundary in the wrong direction. Nudge the selection to a character before proceeding.
1283         extent = baseIsStart ? extent.previous() : extent.next();
1284     }
1285
1286     // Extend to the boundary of the word.
1287
1288     VisiblePosition wordBoundary = positionOfNextBoundaryOfGranularity(extent, WordGranularity, sameDirection);
1289     if (wordBoundary.isNotNull()
1290         && atBoundaryOfGranularity(wordBoundary, WordGranularity, sameDirection)
1291         && initialExtent != wordBoundary) {
1292         extent = wordBoundary;
1293         return (base < extent) ? Range::create(*frame->document(), base, extent) : Range::create(*frame->document(), extent, base);
1294     }
1295     // Conversely, if the initial extent equals the current word boundary, then
1296     // run the rest of this function to see if the selection should extend
1297     // the other direction to the other word.
1298
1299     // If this is where the extent was initially, then iterate in the other direction in the document until we hit the next word.
1300     while (extent.isNotNull()
1301         && !atBoundaryOfGranularity(extent, WordGranularity, sameDirection)
1302         && extent != base
1303         && !atBoundaryOfGranularity(extent, LineGranularity, sameDirection)
1304         && !atBoundaryOfGranularity(extent, LineGranularity, oppositeDirection)) {
1305         extent = baseIsStart ? extent.next() : extent.previous();
1306     }
1307
1308     // Don't let the smart extension make the extent equal the base.
1309     // Expand out to word boundary.
1310     if (extent.isNull() || extent == base)
1311         extent = wordBoundary;
1312     if (extent.isNull())
1313         return nullptr;
1314
1315     return (base < extent) ? Range::create(*frame->document(), base, extent) : Range::create(*frame->document(), extent, base);
1316 }
1317
1318 void WebPage::clearSelection(){
1319     m_startingGestureRange = nullptr;
1320     m_currentBlockSelection = nullptr;
1321     m_page->focusController().focusedOrMainFrame().selection().clear();
1322 }
1323
1324 void WebPage::updateSelectionWithTouches(const IntPoint& point, uint32_t touches, bool baseIsStart, CallbackID callbackID)
1325 {
1326     Frame& frame = m_page->focusController().focusedOrMainFrame();
1327     IntPoint pointInDocument = frame.view()->rootViewToContents(point);
1328     VisiblePosition position = frame.visiblePositionForPoint(pointInDocument);
1329     if (position.isNull()) {
1330         send(Messages::WebPageProxy::TouchesCallback(point, touches, 0, callbackID));
1331         return;
1332     }
1333
1334     RefPtr<Range> range;
1335     VisiblePosition result;
1336     SelectionFlags flags = None;
1337
1338     switch (static_cast<SelectionTouch>(touches)) {
1339     case SelectionTouch::Started:
1340     case SelectionTouch::EndedNotMoving:
1341         break;
1342     
1343     case SelectionTouch::Ended:
1344         if (frame.selection().selection().isContentEditable()) {
1345             result = closestWordBoundaryForPosition(position);
1346             if (result.isNotNull())
1347                 range = Range::create(*frame.document(), result, result);
1348         } else
1349             range = rangeForPointInRootViewCoordinates(frame, point, baseIsStart);
1350         break;
1351
1352     case SelectionTouch::EndedMovingForward:
1353         range = rangeAtWordBoundaryForPosition(&frame, position, baseIsStart, DirectionForward);
1354         break;
1355         
1356     case SelectionTouch::EndedMovingBackward:
1357         range = rangeAtWordBoundaryForPosition(&frame, position, baseIsStart, DirectionBackward);
1358         break;
1359
1360     case SelectionTouch::Moved:
1361         range = rangeForPointInRootViewCoordinates(frame, point, baseIsStart);
1362         break;
1363     }
1364     if (range)
1365         frame.selection().setSelectedRange(range.get(), position.affinity(), true, UserTriggered);
1366
1367     send(Messages::WebPageProxy::TouchesCallback(point, touches, flags, callbackID));
1368 }
1369
1370 void WebPage::selectWithTwoTouches(const WebCore::IntPoint& from, const WebCore::IntPoint& to, uint32_t gestureType, uint32_t gestureState, CallbackID callbackID)
1371 {
1372     Frame& frame = m_page->focusController().focusedOrMainFrame();
1373     VisiblePosition fromPosition = frame.visiblePositionForPoint(frame.view()->rootViewToContents(from));
1374     VisiblePosition toPosition = frame.visiblePositionForPoint(frame.view()->rootViewToContents(to));
1375     RefPtr<Range> range;
1376     if (fromPosition.isNotNull() && toPosition.isNotNull()) {
1377         if (fromPosition < toPosition)
1378             range = Range::create(*frame.document(), fromPosition, toPosition);
1379         else
1380             range = Range::create(*frame.document(), toPosition, fromPosition);
1381         frame.selection().setSelectedRange(range.get(), fromPosition.affinity(), true, UserTriggered);
1382     }
1383
1384     // We can use the same callback for the gestures with one point.
1385     send(Messages::WebPageProxy::GestureCallback(from, gestureType, gestureState, 0, callbackID));
1386 }
1387
1388 void WebPage::extendSelection(uint32_t granularity)
1389 {
1390     Frame& frame = m_page->focusController().focusedOrMainFrame();
1391     // For the moment we handle only WordGranularity.
1392     if (granularity != WordGranularity || !frame.selection().isCaret())
1393         return;
1394
1395     VisiblePosition position = frame.selection().selection().start();
1396     frame.selection().setSelectedRange(wordRangeFromPosition(position).get(), position.affinity(), true, UserTriggered);
1397 }
1398
1399 void WebPage::selectWordBackward()
1400 {
1401     Frame& frame = m_page->focusController().focusedOrMainFrame();
1402     if (!frame.selection().isCaret())
1403         return;
1404
1405     VisiblePosition position = frame.selection().selection().start();
1406     VisiblePosition startPosition = positionOfNextBoundaryOfGranularity(position, WordGranularity, DirectionBackward);
1407     if (startPosition.isNotNull() && startPosition != position)
1408         frame.selection().setSelectedRange(Range::create(*frame.document(), startPosition, position).ptr(), position.affinity(), true, UserTriggered);
1409 }
1410
1411 void WebPage::moveSelectionByOffset(int32_t offset, CallbackID callbackID)
1412 {
1413     Frame& frame = m_page->focusController().focusedOrMainFrame();
1414     
1415     VisiblePosition startPosition = frame.selection().selection().end();
1416     if (startPosition.isNull())
1417         return;
1418     SelectionDirection direction = offset < 0 ? DirectionBackward : DirectionForward;
1419     VisiblePosition position = startPosition;
1420     for (int i = 0; i < abs(offset); ++i) {
1421         position = positionOfNextBoundaryOfGranularity(position, CharacterGranularity, direction);
1422         if (position.isNull())
1423             break;
1424     }
1425     if (position.isNotNull() && startPosition != position)
1426         frame.selection().setSelectedRange(Range::create(*frame.document(), position, position).ptr(), position.affinity(), true, UserTriggered);
1427     send(Messages::WebPageProxy::VoidCallback(callbackID));
1428 }
1429     
1430 void WebPage::startAutoscrollAtPosition(const WebCore::FloatPoint& positionInWindow)
1431 {
1432     if (m_assistedNode && m_assistedNode->renderer())
1433         m_page->mainFrame().eventHandler().startSelectionAutoscroll(m_assistedNode->renderer(), positionInWindow);
1434     else {
1435         Frame& frame = m_page->focusController().focusedOrMainFrame();
1436         VisibleSelection selection = frame.selection().selection();
1437         if (selection.isRange()) {
1438             RefPtr<Range> range = frame.selection().toNormalizedRange();
1439             Node& node = range->startContainer();
1440             auto* renderer = node.renderer();
1441             if (renderer)
1442                 m_page->mainFrame().eventHandler().startSelectionAutoscroll(renderer, positionInWindow);
1443         }
1444     }
1445 }
1446     
1447 void WebPage::cancelAutoscroll()
1448 {
1449     m_page->mainFrame().eventHandler().cancelSelectionAutoscroll();
1450 }
1451
1452 void WebPage::getRectsForGranularityWithSelectionOffset(uint32_t granularity, int32_t offset, CallbackID callbackID)
1453 {
1454     Frame& frame = m_page->focusController().focusedOrMainFrame();
1455     VisibleSelection selection = m_storedSelectionForAccessibility.isNone() ? frame.selection().selection() : m_storedSelectionForAccessibility;
1456     VisiblePosition selectionStart = selection.visibleStart();
1457
1458     if (selectionStart.isNull()) {
1459         send(Messages::WebPageProxy::SelectionRectsCallback({ }, callbackID));
1460         return;
1461     }
1462
1463     auto position = visiblePositionForPositionWithOffset(selectionStart, offset);
1464     SelectionDirection direction = offset < 0 ? DirectionBackward : DirectionForward;
1465
1466     auto range = enclosingTextUnitOfGranularity(position, static_cast<WebCore::TextGranularity>(granularity), direction);
1467     if (!range || range->collapsed()) {
1468         send(Messages::WebPageProxy::SelectionRectsCallback({ }, callbackID));
1469         return;
1470     }
1471
1472     Vector<WebCore::SelectionRect> selectionRects;
1473     range->collectSelectionRectsWithoutUnionInteriorLines(selectionRects);
1474     convertSelectionRectsToRootView(frame.view(), selectionRects);
1475     send(Messages::WebPageProxy::SelectionRectsCallback(selectionRects, callbackID));
1476 }
1477
1478 void WebPage::storeSelectionForAccessibility(bool shouldStore)
1479 {
1480     if (!shouldStore)
1481         m_storedSelectionForAccessibility = VisibleSelection();
1482     else {
1483         Frame& frame = m_page->focusController().focusedOrMainFrame();
1484         m_storedSelectionForAccessibility = frame.selection().selection();
1485     }
1486 }
1487
1488 static RefPtr<Range> rangeNearPositionMatchesText(const VisiblePosition& position, RefPtr<Range> originalRange, const String& matchText, RefPtr<Range> selectionRange)
1489 {
1490     auto range = Range::create(selectionRange->ownerDocument(), selectionRange->startPosition(), position.deepEquivalent().parentAnchoredEquivalent());
1491     unsigned targetOffset = TextIterator::rangeLength(range.ptr(), true);
1492     return findClosestPlainText(*selectionRange.get(), matchText, { }, targetOffset);
1493 }
1494
1495 void WebPage::getRectsAtSelectionOffsetWithText(int32_t offset, const String& text, CallbackID callbackID)
1496 {
1497     Frame& frame = m_page->focusController().focusedOrMainFrame();
1498     uint32_t length = text.length();
1499     VisibleSelection selection = m_storedSelectionForAccessibility.isNone() ? frame.selection().selection() : m_storedSelectionForAccessibility;
1500     VisiblePosition selectionStart = selection.visibleStart();
1501     VisiblePosition selectionEnd = selection.visibleEnd();
1502
1503     if (selectionStart.isNull() || selectionEnd.isNull()) {
1504         send(Messages::WebPageProxy::SelectionRectsCallback({ }, callbackID));
1505         return;
1506     }
1507
1508     auto startPosition = visiblePositionForPositionWithOffset(selectionStart, offset);
1509     auto endPosition = visiblePositionForPositionWithOffset(startPosition, length);
1510     auto range = Range::create(*frame.document(), startPosition, endPosition);
1511
1512     if (range->collapsed()) {
1513         send(Messages::WebPageProxy::SelectionRectsCallback({ }, callbackID));
1514         return;
1515     }
1516
1517     String rangeText = plainTextReplacingNoBreakSpace(range.ptr(), TextIteratorDefaultBehavior, true);
1518     if (rangeText != text) {
1519         auto selectionRange = selection.toNormalizedRange();
1520         // Try to search for a range which is the closest to the position within the selection range that matches the passed in text.
1521         if (auto wordRange = rangeNearPositionMatchesText(startPosition, range.ptr(), text, selectionRange)) {
1522             if (!wordRange->collapsed())
1523                 range = *wordRange;
1524         }
1525     }
1526
1527     Vector<WebCore::SelectionRect> selectionRects;
1528     range->collectSelectionRectsWithoutUnionInteriorLines(selectionRects);
1529     convertSelectionRectsToRootView(frame.view(), selectionRects);
1530     send(Messages::WebPageProxy::SelectionRectsCallback(selectionRects, callbackID));
1531 }
1532
1533 VisiblePosition WebPage::visiblePositionInFocusedNodeForPoint(const Frame& frame, const IntPoint& point, bool isInteractingWithAssistedNode)
1534 {
1535     IntPoint adjustedPoint(frame.view()->rootViewToContents(point));
1536     IntPoint constrainedPoint = m_assistedNode && isInteractingWithAssistedNode ? constrainPoint(adjustedPoint, frame, *m_assistedNode) : adjustedPoint;
1537     return frame.visiblePositionForPoint(constrainedPoint);
1538 }
1539
1540 void WebPage::selectPositionAtPoint(const WebCore::IntPoint& point, bool isInteractingWithAssistedNode, CallbackID callbackID)
1541 {
1542     auto& frame = m_page->focusController().focusedOrMainFrame();
1543     VisiblePosition position = visiblePositionInFocusedNodeForPoint(frame, point, isInteractingWithAssistedNode);
1544     
1545     if (position.isNotNull())
1546         frame.selection().setSelectedRange(Range::create(*frame.document(), position, position).ptr(), position.affinity(), true, UserTriggered);
1547     send(Messages::WebPageProxy::VoidCallback(callbackID));
1548 }
1549
1550 void WebPage::selectPositionAtBoundaryWithDirection(const WebCore::IntPoint& point, uint32_t granularity, uint32_t direction, bool isInteractingWithAssistedNode, CallbackID callbackID)
1551 {
1552     auto& frame = m_page->focusController().focusedOrMainFrame();
1553     VisiblePosition position = visiblePositionInFocusedNodeForPoint(frame, point, isInteractingWithAssistedNode);
1554
1555     if (position.isNotNull()) {
1556         position = positionOfNextBoundaryOfGranularity(position, static_cast<WebCore::TextGranularity>(granularity), static_cast<SelectionDirection>(direction));
1557         if (position.isNotNull())
1558             frame.selection().setSelectedRange(Range::create(*frame.document(), position, position).ptr(), UPSTREAM, true, UserTriggered);
1559     }
1560     send(Messages::WebPageProxy::VoidCallback(callbackID));
1561 }
1562
1563 void WebPage::moveSelectionAtBoundaryWithDirection(uint32_t granularity, uint32_t direction, CallbackID callbackID)
1564 {
1565     Frame& frame = m_page->focusController().focusedOrMainFrame();
1566     
1567     if (!frame.selection().selection().isNone()) {
1568         bool isForward = (direction == DirectionForward || direction == DirectionRight);
1569         VisiblePosition position = (isForward) ? frame.selection().selection().visibleEnd() : frame.selection().selection().visibleStart();
1570         position = positionOfNextBoundaryOfGranularity(position, static_cast<WebCore::TextGranularity>(granularity), static_cast<SelectionDirection>(direction));
1571         if (position.isNotNull())
1572             frame.selection().setSelectedRange(Range::create(*frame.document(), position, position).ptr(), isForward? UPSTREAM : DOWNSTREAM, true, UserTriggered);
1573     }
1574     send(Messages::WebPageProxy::VoidCallback(callbackID));
1575 }
1576
1577 RefPtr<Range> WebPage::rangeForGranularityAtPoint(Frame& frame, const WebCore::IntPoint& point, uint32_t granularity, bool isInteractingWithAssistedNode)
1578 {
1579     VisiblePosition position = visiblePositionInFocusedNodeForPoint(frame, point, isInteractingWithAssistedNode);
1580
1581     RefPtr<Range> range;
1582     switch (static_cast<WebCore::TextGranularity>(granularity)) {
1583     case WordGranularity:
1584         range = wordRangeFromPosition(position);
1585         break;
1586     case SentenceGranularity:
1587         range = enclosingTextUnitOfGranularity(position, SentenceGranularity, DirectionForward);
1588         break;
1589     case ParagraphGranularity:
1590         range = enclosingTextUnitOfGranularity(position, ParagraphGranularity, DirectionForward);
1591         break;
1592     case DocumentGranularity:
1593         frame.selection().selectAll();
1594         break;
1595     default:
1596         break;
1597     }
1598     return range;
1599 }
1600
1601 static inline bool rectIsTooBigForSelection(const IntRect& blockRect, const Frame& frame)
1602 {
1603     const float factor = 0.97;
1604     return blockRect.height() > frame.view()->unobscuredContentRect().height() * factor;
1605 }
1606
1607 void WebPage::selectTextWithGranularityAtPoint(const WebCore::IntPoint& point, uint32_t granularity, bool isInteractingWithAssistedNode, CallbackID callbackID)
1608 {
1609     auto& frame = m_page->focusController().focusedOrMainFrame();
1610     RefPtr<Range> range = rangeForGranularityAtPoint(frame, point, granularity, isInteractingWithAssistedNode);
1611     if (!isInteractingWithAssistedNode) {
1612         m_blockSelectionDesiredSize.setWidth(blockSelectionStartWidth);
1613         m_blockSelectionDesiredSize.setHeight(blockSelectionStartHeight);
1614         m_currentBlockSelection = nullptr;
1615         auto* renderer = range ? range->startContainer().renderer() : nullptr;
1616         if (renderer && renderer->style().preserveNewline())
1617             m_blockRectForTextSelection = renderer->absoluteBoundingBoxRect(true);
1618         else {
1619             auto paragraphRange = enclosingTextUnitOfGranularity(visiblePositionInFocusedNodeForPoint(frame, point, isInteractingWithAssistedNode), ParagraphGranularity, DirectionForward);
1620             if (paragraphRange && !paragraphRange->collapsed())
1621                 m_blockRectForTextSelection = selectionBoxForRange(paragraphRange.get());
1622         }
1623         
1624         if (rectIsTooBigForSelection(m_blockRectForTextSelection, frame))
1625             m_blockRectForTextSelection.setHeight(0);
1626     }
1627
1628     if (range)
1629         frame.selection().setSelectedRange(range.get(), UPSTREAM, true, UserTriggered);
1630     m_initialSelection = range;
1631     send(Messages::WebPageProxy::VoidCallback(callbackID));
1632 }
1633
1634 void WebPage::beginSelectionInDirection(uint32_t direction, CallbackID callbackID)
1635 {
1636     m_selectionAnchor = (static_cast<SelectionDirection>(direction) == DirectionLeft) ? Start : End;
1637     send(Messages::WebPageProxy::UnsignedCallback(m_selectionAnchor == Start, callbackID));
1638 }
1639
1640 void WebPage::updateSelectionWithExtentPointAndBoundary(const WebCore::IntPoint& point, uint32_t granularity, bool isInteractingWithAssistedNode, CallbackID callbackID)
1641 {
1642     auto& frame = m_page->focusController().focusedOrMainFrame();
1643     VisiblePosition position = visiblePositionInFocusedNodeForPoint(frame, point, isInteractingWithAssistedNode);
1644     RefPtr<Range> newRange = rangeForGranularityAtPoint(frame, point, granularity, isInteractingWithAssistedNode);
1645     
1646     if (position.isNull() || !m_initialSelection || !newRange) {
1647         send(Messages::WebPageProxy::UnsignedCallback(false, callbackID));
1648         return;
1649     }
1650     
1651     RefPtr<Range> range;
1652     VisiblePosition selectionStart = m_initialSelection->startPosition();
1653     VisiblePosition selectionEnd = m_initialSelection->endPosition();
1654
1655     if (position > m_initialSelection->endPosition())
1656         selectionEnd = newRange->endPosition();
1657     else if (position < m_initialSelection->startPosition())
1658         selectionStart = newRange->startPosition();
1659     
1660     if (selectionStart.isNotNull() && selectionEnd.isNotNull())
1661         range = Range::create(*frame.document(), selectionStart, selectionEnd);
1662     
1663     if (range)
1664         frame.selection().setSelectedRange(range.get(), UPSTREAM, true, UserTriggered);
1665     
1666     send(Messages::WebPageProxy::UnsignedCallback(selectionStart == m_initialSelection->startPosition(), callbackID));
1667 }
1668
1669 void WebPage::updateSelectionWithExtentPoint(const WebCore::IntPoint& point, bool isInteractingWithAssistedNode, CallbackID callbackID)
1670 {
1671     auto& frame = m_page->focusController().focusedOrMainFrame();
1672     VisiblePosition position = visiblePositionInFocusedNodeForPoint(frame, point, isInteractingWithAssistedNode);
1673
1674     if (position.isNull()) {
1675         send(Messages::WebPageProxy::UnsignedCallback(false, callbackID));
1676         return;
1677     }
1678
1679     RefPtr<Range> range;
1680     VisiblePosition selectionStart;
1681     VisiblePosition selectionEnd;
1682     
1683     if (m_selectionAnchor == Start) {
1684         selectionStart = frame.selection().selection().visibleStart();
1685         selectionEnd = position;
1686
1687         if (position <= selectionStart) {
1688             selectionStart = selectionStart.previous();
1689             selectionEnd = frame.selection().selection().visibleEnd();
1690             m_selectionAnchor = End;
1691         }
1692     } else {
1693         selectionStart = position;
1694         selectionEnd = frame.selection().selection().visibleEnd();
1695         
1696         if (position >= selectionEnd) {
1697             selectionStart = frame.selection().selection().visibleStart();
1698             selectionEnd = selectionEnd.next();
1699             m_selectionAnchor = Start;
1700         }
1701     }
1702     
1703     if (selectionStart.isNotNull() && selectionEnd.isNotNull())
1704         range = Range::create(*frame.document(), selectionStart, selectionEnd);
1705
1706     if (range)
1707         frame.selection().setSelectedRange(range.get(), UPSTREAM, true, UserTriggered);
1708
1709     send(Messages::WebPageProxy::UnsignedCallback(m_selectionAnchor == Start, callbackID));
1710 }
1711
1712 void WebPage::convertSelectionRectsToRootView(FrameView* view, Vector<SelectionRect>& selectionRects)
1713 {
1714     for (size_t i = 0; i < selectionRects.size(); ++i) {
1715         SelectionRect& currentRect = selectionRects[i];
1716         currentRect.setRect(view->contentsToRootView(currentRect.rect()));
1717     }
1718 }
1719
1720 void WebPage::requestDictationContext(CallbackID callbackID)
1721 {
1722     Frame& frame = m_page->focusController().focusedOrMainFrame();
1723     VisiblePosition startPosition = frame.selection().selection().start();
1724     VisiblePosition endPosition = frame.selection().selection().end();
1725     const unsigned dictationContextWordCount = 5;
1726
1727     String selectedText;
1728     if (frame.selection().isRange())
1729         selectedText = plainTextReplacingNoBreakSpace(frame.selection().selection().toNormalizedRange().get());
1730
1731     String contextBefore;
1732     if (startPosition != startOfEditableContent(startPosition)) {
1733         VisiblePosition currentPosition = startPosition;
1734         VisiblePosition lastPosition = startPosition;
1735         for (unsigned i = 0; i < dictationContextWordCount; ++i) {
1736             currentPosition = startOfWord(positionOfNextBoundaryOfGranularity(lastPosition, WordGranularity, DirectionBackward));
1737             if (currentPosition.isNull())
1738                 break;
1739             lastPosition = currentPosition;
1740         }
1741         if (lastPosition.isNotNull() && lastPosition != startPosition)
1742             contextBefore = plainTextReplacingNoBreakSpace(Range::create(*frame.document(), lastPosition, startPosition).ptr());
1743     }
1744
1745     String contextAfter;
1746     if (endPosition != endOfEditableContent(endPosition)) {
1747         VisiblePosition currentPosition = endPosition;
1748         VisiblePosition lastPosition = endPosition;
1749         for (unsigned i = 0; i < dictationContextWordCount; ++i) {
1750             currentPosition = endOfWord(positionOfNextBoundaryOfGranularity(lastPosition, WordGranularity, DirectionForward));
1751             if (currentPosition.isNull())
1752                 break;
1753             lastPosition = currentPosition;
1754         }
1755         if (lastPosition.isNotNull() && lastPosition != endPosition)
1756             contextAfter = plainTextReplacingNoBreakSpace(Range::create(*frame.document(), endPosition, lastPosition).ptr());
1757     }
1758
1759     send(Messages::WebPageProxy::SelectionContextCallback(selectedText, contextBefore, contextAfter, callbackID));
1760 }
1761
1762 void WebPage::replaceSelectedText(const String& oldText, const String& newText)
1763 {
1764     Frame& frame = m_page->focusController().focusedOrMainFrame();
1765     RefPtr<Range> wordRange = frame.selection().isCaret() ? wordRangeFromPosition(frame.selection().selection().start()) : frame.selection().toNormalizedRange();
1766     if (plainTextReplacingNoBreakSpace(wordRange.get()) != oldText)
1767         return;
1768     
1769     frame.editor().setIgnoreSelectionChanges(true);
1770     frame.selection().setSelectedRange(wordRange.get(), UPSTREAM, true);
1771     frame.editor().insertText(newText, 0);
1772     frame.editor().setIgnoreSelectionChanges(false);
1773 }
1774
1775 void WebPage::replaceDictatedText(const String& oldText, const String& newText)
1776 {
1777     Frame& frame = m_page->focusController().focusedOrMainFrame();
1778     if (frame.selection().isNone())
1779         return;
1780     
1781     if (frame.selection().isRange()) {
1782         frame.editor().deleteSelectionWithSmartDelete(false);
1783         return;
1784     }
1785     VisiblePosition position = frame.selection().selection().start();
1786     for (size_t i = 0; i < oldText.length(); ++i)
1787         position = position.previous();
1788     if (position.isNull())
1789         position = startOfDocument(static_cast<Node*>(frame.document()->documentElement()));
1790     RefPtr<Range> range = Range::create(*frame.document(), position, frame.selection().selection().start());
1791
1792     if (plainTextReplacingNoBreakSpace(range.get()) != oldText)
1793         return;
1794
1795     // We don't want to notify the client that the selection has changed until we are done inserting the new text.
1796     frame.editor().setIgnoreSelectionChanges(true);
1797     frame.selection().setSelectedRange(range.get(), UPSTREAM, true);
1798     frame.editor().insertText(newText, 0);
1799     frame.editor().setIgnoreSelectionChanges(false);
1800 }
1801
1802 void WebPage::requestAutocorrectionData(const String& textForAutocorrection, CallbackID callbackID)
1803 {
1804     Frame& frame = m_page->focusController().focusedOrMainFrame();
1805     if (!frame.selection().isCaret()) {
1806         send(Messages::WebPageProxy::AutocorrectionDataCallback(Vector<FloatRect>(), String(), 0, 0, callbackID));
1807         return;
1808     }
1809
1810     VisiblePosition position = frame.selection().selection().start();
1811     RefPtr<Range> range = wordRangeFromPosition(position);
1812     if (!range) {
1813         send(Messages::WebPageProxy::AutocorrectionDataCallback(Vector<FloatRect>(), String(), 0, 0, callbackID));
1814         return;
1815     }
1816
1817     String textForRange = plainTextReplacingNoBreakSpace(range.get());
1818     const unsigned maxSearchAttempts = 5;
1819     for (size_t i = 0;  i < maxSearchAttempts && textForRange != textForAutocorrection; ++i)
1820     {
1821         position = range->startPosition().previous();
1822         if (position.isNull() || position == range->startPosition())
1823             break;
1824         range = Range::create(*frame.document(), wordRangeFromPosition(position)->startPosition(), range->endPosition());
1825         textForRange = plainTextReplacingNoBreakSpace(range.get());
1826     }
1827
1828     Vector<SelectionRect> selectionRects;
1829     if (textForRange == textForAutocorrection)
1830         range->collectSelectionRects(selectionRects);
1831
1832     Vector<FloatRect> rectsForText;
1833     rectsForText.grow(selectionRects.size());
1834
1835     convertSelectionRectsToRootView(frame.view(), selectionRects);
1836     for (size_t i = 0; i < selectionRects.size(); i++)
1837         rectsForText[i] = selectionRects[i].rect();
1838
1839     bool multipleFonts = false;
1840     CTFontRef font = nil;
1841     if (auto* coreFont = frame.editor().fontForSelection(multipleFonts))
1842         font = coreFont->getCTFont();
1843
1844     CGFloat fontSize = CTFontGetSize(font);
1845     uint64_t fontTraits = CTFontGetSymbolicTraits(font);
1846     RetainPtr<NSString> fontName = adoptNS((NSString *)CTFontCopyFamilyName(font));
1847     send(Messages::WebPageProxy::AutocorrectionDataCallback(rectsForText, fontName.get(), fontSize, fontTraits, callbackID));
1848 }
1849
1850 void WebPage::applyAutocorrection(const String& correction, const String& originalText, CallbackID callbackID)
1851 {
1852     bool correctionApplied;
1853     syncApplyAutocorrection(correction, originalText, correctionApplied);
1854     send(Messages::WebPageProxy::StringCallback(correctionApplied ? correction : String(), callbackID));
1855 }
1856
1857 Seconds WebPage::eventThrottlingDelay() const
1858 {
1859     auto behaviorOverride = m_page->eventThrottlingBehaviorOverride();
1860     if (behaviorOverride) {
1861         switch (behaviorOverride.value()) {
1862         case EventThrottlingBehavior::Responsive:
1863             return 0_s;
1864         case EventThrottlingBehavior::Unresponsive:
1865             return 1_s;
1866         }
1867     }
1868
1869     if (m_isInStableState || m_estimatedLatency <= Seconds(1.0 / 60))
1870         return 0_s;
1871
1872     return std::min(m_estimatedLatency * 2, 1_s);
1873 }
1874
1875 void WebPage::syncApplyAutocorrection(const String& correction, const String& originalText, bool& correctionApplied)
1876 {
1877     correctionApplied = false;
1878
1879     Frame& frame = m_page->focusController().focusedOrMainFrame();
1880     if (!frame.selection().isCaretOrRange())
1881         return;
1882
1883     RefPtr<Range> range;
1884     String textForRange;
1885
1886     if (frame.selection().isCaret()) {
1887         VisiblePosition position = frame.selection().selection().start();
1888         range = wordRangeFromPosition(position);
1889         textForRange = plainTextReplacingNoBreakSpace(range.get());
1890         if (textForRange != originalText) {
1891             // Search for the original text before the selection caret.
1892             for (size_t i = 0; i < originalText.length(); ++i)
1893                 position = position.previous();
1894             if (position.isNull())
1895                 position = startOfDocument(static_cast<Node*>(frame.document()->documentElement()));
1896             range = Range::create(*frame.document(), position, frame.selection().selection().start());
1897             if (range)
1898                 textForRange = (range) ? plainTextReplacingNoBreakSpace(range.get()) : emptyString();
1899             unsigned loopCount = 0;
1900             const unsigned maxPositionsAttempts = 10;
1901             while (textForRange.length() && textForRange.length() > originalText.length() && loopCount < maxPositionsAttempts) {
1902                 position = position.next();
1903                 if (position.isNotNull() && position >= frame.selection().selection().start())
1904                     range = nullptr;
1905                 else
1906                     range = Range::create(*frame.document(), position, frame.selection().selection().start());
1907                 textForRange = (range) ? plainTextReplacingNoBreakSpace(range.get()) : emptyString();
1908                 loopCount++;
1909             }
1910         }
1911     } else {
1912         // Range selection.
1913         range = frame.selection().toNormalizedRange();
1914         if (!range) {
1915             correctionApplied = false;
1916             return;
1917         }
1918         textForRange = plainTextReplacingNoBreakSpace(range.get());
1919     }
1920
1921     if (textForRange != originalText) {
1922         correctionApplied = false;
1923         return;
1924     }
1925     
1926     // Correctly determine affinity, using logic currently only present in VisiblePosition
1927     EAffinity affinity = DOWNSTREAM;
1928     if (range && range->collapsed())
1929         affinity = VisiblePosition(range->startPosition(), UPSTREAM).affinity();
1930     
1931     frame.selection().setSelectedRange(range.get(), affinity, true);
1932     if (correction.length())
1933         frame.editor().insertText(correction, 0, originalText.isEmpty() ? TextEventInputKeyboard : TextEventInputAutocompletion);
1934     else
1935         frame.editor().deleteWithDirection(DirectionBackward, CharacterGranularity, false, true);
1936     correctionApplied = true;
1937 }
1938
1939 static void computeAutocorrectionContext(Frame& frame, String& contextBefore, String& markedText, String& selectedText, String& contextAfter, uint64_t& location, uint64_t& length)
1940 {
1941     RefPtr<Range> range;
1942     VisiblePosition startPosition = frame.selection().selection().start();
1943     VisiblePosition endPosition = frame.selection().selection().end();
1944     location = NSNotFound;
1945     length = 0;
1946     const unsigned minContextWordCount = 3;
1947     const unsigned minContextLenght = 12;
1948     const unsigned maxContextLength = 30;
1949
1950     if (frame.selection().isRange())
1951         selectedText = plainTextReplacingNoBreakSpace(frame.selection().selection().toNormalizedRange().get());
1952
1953     if (auto compositionRange = frame.editor().compositionRange()) {
1954         range = Range::create(*frame.document(), compositionRange->startPosition(), startPosition);
1955         String markedTextBefore;
1956         if (range)
1957             markedTextBefore = plainTextReplacingNoBreakSpace(range.get());
1958         range = Range::create(*frame.document(), endPosition, compositionRange->endPosition());
1959         String markedTextAfter;
1960         if (range)
1961             markedTextAfter = plainTextReplacingNoBreakSpace(range.get());
1962         markedText = markedTextBefore + selectedText + markedTextAfter;
1963         if (!markedText.isEmpty()) {
1964             location = markedTextBefore.length();
1965             length = selectedText.length();
1966         }
1967     } else {
1968         if (startPosition != startOfEditableContent(startPosition)) {
1969             VisiblePosition currentPosition = startPosition;
1970             VisiblePosition previousPosition;
1971             unsigned totalContextLength = 0;
1972             for (unsigned i = 0; i < minContextWordCount; ++i) {
1973                 if (contextBefore.length() >= minContextLenght)
1974                     break;
1975                 previousPosition = startOfWord(positionOfNextBoundaryOfGranularity(currentPosition, WordGranularity, DirectionBackward));
1976                 if (previousPosition.isNull())
1977                     break;
1978                 String currentWord = plainTextReplacingNoBreakSpace(Range::create(*frame.document(), previousPosition, currentPosition).ptr());
1979                 totalContextLength += currentWord.length();
1980                 if (totalContextLength >= maxContextLength)
1981                     break;
1982                 currentPosition = previousPosition;
1983             }
1984             if (currentPosition.isNotNull() && currentPosition != startPosition) {
1985                 contextBefore = plainTextReplacingNoBreakSpace(Range::create(*frame.document(), currentPosition, startPosition).ptr());
1986                 if (atBoundaryOfGranularity(currentPosition, ParagraphGranularity, DirectionBackward))
1987                     contextBefore = makeString("\n "_s, contextBefore);
1988             }
1989         }
1990
1991         if (endPosition != endOfEditableContent(endPosition)) {
1992             VisiblePosition nextPosition;
1993             if (!atBoundaryOfGranularity(endPosition, WordGranularity, DirectionForward) && withinTextUnitOfGranularity(endPosition, WordGranularity, DirectionForward))
1994                 nextPosition = positionOfNextBoundaryOfGranularity(endPosition, WordGranularity, DirectionForward);
1995             if (nextPosition.isNotNull())
1996                 contextAfter = plainTextReplacingNoBreakSpace(Range::create(*frame.document(), endPosition, nextPosition).ptr());
1997         }
1998     }
1999 }
2000
2001 void WebPage::requestAutocorrectionContext(CallbackID callbackID)
2002 {
2003     String contextBefore;
2004     String contextAfter;
2005     String selectedText;
2006     String markedText;
2007     uint64_t location;
2008     uint64_t length;
2009
2010     computeAutocorrectionContext(m_page->focusController().focusedOrMainFrame(), contextBefore, markedText, selectedText, contextAfter, location, length);
2011
2012     send(Messages::WebPageProxy::AutocorrectionContextCallback(contextBefore, markedText, selectedText, contextAfter, location, length, callbackID));
2013 }
2014
2015 void WebPage::getAutocorrectionContext(String& contextBefore, String& markedText, String& selectedText, String& contextAfter, uint64_t& location, uint64_t& length)
2016 {
2017     computeAutocorrectionContext(m_page->focusController().focusedOrMainFrame(), contextBefore, markedText, selectedText, contextAfter, location, length);
2018 }
2019
2020 static HTMLAnchorElement* containingLinkElement(Element* element)
2021 {
2022     for (auto& currentElement : elementLineage(element)) {
2023         if (currentElement.isLink() && is<HTMLAnchorElement>(currentElement))
2024             return downcast<HTMLAnchorElement>(&currentElement);
2025     }
2026     return nullptr;
2027 }
2028
2029 static inline bool isAssistableElement(Element& node)
2030 {
2031     if (is<HTMLSelectElement>(node))
2032         return true;
2033     if (is<HTMLTextAreaElement>(node))
2034         return true;
2035     if (is<HTMLInputElement>(node)) {
2036         HTMLInputElement& inputElement = downcast<HTMLInputElement>(node);
2037         // FIXME: This laundry list of types is not a good way to factor this. Need a suitable function on HTMLInputElement itself.
2038 #if ENABLE(INPUT_TYPE_COLOR)
2039         if (inputElement.isColorControl())
2040             return true;
2041 #endif
2042         return inputElement.isTextField() || inputElement.isDateField() || inputElement.isDateTimeLocalField() || inputElement.isMonthField() || inputElement.isTimeField();
2043     }
2044     return node.isContentEditable();
2045 }
2046
2047 void WebPage::getPositionInformation(const InteractionInformationRequest& request, InteractionInformationAtPosition& info)
2048 {
2049     info.request = request;
2050
2051     FloatPoint adjustedPoint;
2052     Node* hitNode = m_page->mainFrame().nodeRespondingToClickEvents(request.point, adjustedPoint);
2053
2054     info.nodeAtPositionIsAssistedNode = (hitNode == m_assistedNode);
2055     if (m_assistedNode) {
2056         const Frame& frame = m_page->focusController().focusedOrMainFrame();
2057         if (frame.editor().hasComposition()) {
2058             const uint32_t kHitAreaWidth = 66;
2059             const uint32_t kHitAreaHeight = 66;
2060             FrameView& view = *frame.view();
2061             IntPoint adjustedPoint(view.rootViewToContents(request.point));
2062             IntPoint constrainedPoint = m_assistedNode ? constrainPoint(adjustedPoint, frame, *m_assistedNode) : adjustedPoint;
2063             VisiblePosition position = frame.visiblePositionForPoint(constrainedPoint);
2064
2065             RefPtr<Range> compositionRange = frame.editor().compositionRange();
2066             if (position < compositionRange->startPosition())
2067                 position = compositionRange->startPosition();
2068             else if (position > compositionRange->endPosition())
2069                 position = compositionRange->endPosition();
2070             IntRect caretRect = view.contentsToRootView(position.absoluteCaretBounds());
2071             float deltaX = abs(caretRect.x() + (caretRect.width() / 2) - request.point.x());
2072             float deltaYFromTheTop = abs(caretRect.y() - request.point.y());
2073             float deltaYFromTheBottom = abs(caretRect.y() + caretRect.height() - request.point.y());
2074
2075             info.isNearMarkedText = !(deltaX > kHitAreaWidth || deltaYFromTheTop > kHitAreaHeight || deltaYFromTheBottom > kHitAreaHeight);
2076         }
2077     }
2078     bool elementIsLinkOrImage = false;
2079     if (hitNode) {
2080         Element* element = is<Element>(*hitNode) ? downcast<Element>(hitNode) : nullptr;
2081         if (element) {
2082             info.isElement = true;
2083             info.idAttribute = element->getIdAttribute();
2084             Element* linkElement = nullptr;
2085             if (element->renderer() && element->renderer()->isRenderImage()) {
2086                 elementIsLinkOrImage = true;
2087                 linkElement = containingLinkElement(element);
2088             } else if (element->isLink()) {
2089                 linkElement = element;
2090                 elementIsLinkOrImage = true;
2091             }
2092
2093             if (elementIsLinkOrImage) {
2094                 if (linkElement) {
2095                     info.isLink = true;
2096
2097                     if (request.includeSnapshot) {
2098                         // Ensure that the image contains at most 600K pixels, so that it is not too big.
2099                         if (RefPtr<WebImage> snapshot = snapshotNode(*element, SnapshotOptionsShareable, 600 * 1024))
2100                             info.image = &snapshot->bitmap();
2101                     }
2102
2103                     if (request.includeLinkIndicator) {
2104                         RefPtr<Range> linkRange = rangeOfContents(*linkElement);
2105                         if (linkRange) {
2106                             float deviceScaleFactor = corePage()->deviceScaleFactor();
2107                             const float marginInPoints = 4;
2108
2109                             RefPtr<TextIndicator> textIndicator = TextIndicator::createWithRange(*linkRange, TextIndicatorOptionTightlyFitContent | TextIndicatorOptionRespectTextColor | TextIndicatorOptionPaintBackgrounds | TextIndicatorOptionUseBoundingRectAndPaintAllContentForComplexRanges |
2110                                 TextIndicatorOptionIncludeMarginIfRangeMatchesSelection, TextIndicatorPresentationTransition::None, FloatSize(marginInPoints * deviceScaleFactor, marginInPoints * deviceScaleFactor));
2111
2112                             if (textIndicator)
2113                                 info.linkIndicator = textIndicator->data();
2114                         }
2115                     }
2116
2117 #if ENABLE(DATA_DETECTION)
2118                     info.isDataDetectorLink = DataDetection::isDataDetectorLink(*element);
2119                     if (info.isDataDetectorLink) {
2120                         const int dataDetectionExtendedContextLength = 350;
2121                         info.dataDetectorIdentifier = DataDetection::dataDetectorIdentifier(*element);
2122                         info.dataDetectorResults = element->document().frame()->dataDetectionResults();
2123                         if (DataDetection::requiresExtendedContext(*element)) {
2124                             RefPtr<Range> linkRange = Range::create(element->document());
2125                             linkRange->selectNodeContents(*element);
2126                             info.textBefore = plainTextReplacingNoBreakSpace(rangeExpandedByCharactersInDirectionAtWordBoundary(linkRange->startPosition(), dataDetectionExtendedContextLength, DirectionBackward).get(), TextIteratorDefaultBehavior, true);
2127                             info.textAfter = plainTextReplacingNoBreakSpace(rangeExpandedByCharactersInDirectionAtWordBoundary(linkRange->endPosition(), dataDetectionExtendedContextLength, DirectionForward).get(), TextIteratorDefaultBehavior, true);
2128                         }
2129                     }
2130 #endif
2131                 }
2132                 if (element->renderer() && element->renderer()->isRenderImage()) {
2133                     info.isImage = true;
2134                     auto& renderImage = downcast<RenderImage>(*(element->renderer()));
2135                     if (renderImage.cachedImage() && !renderImage.cachedImage()->errorOccurred()) {
2136                         if (Image* image = renderImage.cachedImage()->imageForRenderer(&renderImage)) {
2137                             if (image->width() > 1 && image->height() > 1) {
2138                                 info.imageURL = element->document().completeURL(renderImage.cachedImage()->url());
2139                                 info.isAnimatedImage = image->isAnimated();
2140
2141                                 if (request.includeSnapshot) {
2142                                     FloatSize screenSizeInPixels = screenSize();
2143                                     screenSizeInPixels.scale(corePage()->deviceScaleFactor());
2144                                     FloatSize scaledSize = largestRectWithAspectRatioInsideRect(image->size().width() / image->size().height(), FloatRect(0, 0, screenSizeInPixels.width(), screenSizeInPixels.height())).size();
2145                                     FloatSize bitmapSize = scaledSize.width() < image->size().width() ? scaledSize : image->size();
2146                                     // FIXME: Only select ExtendedColor on images known to need wide gamut
2147                                     ShareableBitmap::Configuration bitmapConfiguration;
2148                                     bitmapConfiguration.colorSpace.cgColorSpace = screenColorSpace(m_page->mainFrame().view());
2149                                     if (RefPtr<ShareableBitmap> sharedBitmap = ShareableBitmap::createShareable(IntSize(bitmapSize), bitmapConfiguration)) {
2150                                         auto graphicsContext = sharedBitmap->createGraphicsContext();
2151                                         graphicsContext->drawImage(*image, FloatRect(0, 0, bitmapSize.width(), bitmapSize.height()));
2152                                         info.image = sharedBitmap;
2153                                     }
2154                                 }
2155                             }
2156                         }
2157                     }
2158                 }
2159             }
2160             if (linkElement)
2161                 info.url = linkElement->document().completeURL(stripLeadingAndTrailingHTMLSpaces(linkElement->getAttribute(HTMLNames::hrefAttr)));
2162             info.title = element->attributeWithoutSynchronization(HTMLNames::titleAttr).string();
2163             if (linkElement && info.title.isEmpty())
2164                 info.title = element->innerText();
2165             if (element->renderer())
2166                 info.touchCalloutEnabled = element->renderer()->style().touchCalloutEnabled();
2167
2168             if (RenderElement* renderer = element->renderer()) {
2169                 if (renderer->isRenderImage())
2170                     info.bounds = downcast<RenderImage>(*renderer).absoluteContentQuad().enclosingBoundingBox();
2171                 else
2172                     info.bounds = renderer->absoluteBoundingBoxRect();
2173
2174                 if (!renderer->document().frame()->isMainFrame()) {
2175                     FrameView *view = renderer->document().frame()->view();
2176                     info.bounds = view->contentsToRootView(info.bounds);
2177                 }
2178             }
2179         }
2180     }
2181
2182     if (!elementIsLinkOrImage) {
2183         HitTestResult result = m_page->mainFrame().eventHandler().hitTestResultAtPoint(request.point, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowUserAgentShadowContent | HitTestRequest::AllowChildFrameContent);
2184         hitNode = result.innerNode();
2185         // Hit test could return HTMLHtmlElement that has no renderer, if the body is smaller than the document.
2186         if (hitNode && hitNode->renderer()) {
2187             RenderObject* renderer = hitNode->renderer();
2188             m_page->focusController().setFocusedFrame(result.innerNodeFrame());
2189             info.bounds = renderer->absoluteBoundingBoxRect(true);
2190             // We don't want to select blocks that are larger than 97% of the visible area of the document.
2191             if (is<HTMLAttachmentElement>(*hitNode)) {
2192                 info.isAttachment = true;
2193                 const HTMLAttachmentElement& attachment = downcast<HTMLAttachmentElement>(*hitNode);
2194                 info.title = attachment.attachmentTitle();
2195                 if (attachment.file())
2196                     info.url = URL::fileURLWithFileSystemPath(downcast<HTMLAttachmentElement>(*hitNode).file()->path());
2197             } else {
2198                 info.isSelectable = renderer->style().userSelect() != UserSelect::None;
2199                 if (info.isSelectable && !hitNode->isTextNode())
2200                     info.isSelectable = !isAssistableElement(*downcast<Element>(hitNode)) && !rectIsTooBigForSelection(info.bounds, *result.innerNodeFrame());
2201             }
2202 #if PLATFORM(IOSMAC)
2203             bool isInsideFixedPosition;
2204             VisiblePosition caretPosition(renderer->positionForPoint(request.point, nullptr));
2205             info.caretRect = caretPosition.absoluteCaretBounds(&isInsideFixedPosition);
2206 #endif
2207         }
2208     }
2209
2210     // Prevent the callout bar from showing when tapping on the datalist button.
2211 #if ENABLE(DATALIST_ELEMENT)
2212     if (is<HTMLInputElement>(*hitNode)) {
2213         const HTMLInputElement& input = downcast<HTMLInputElement>(*hitNode);
2214         if (input.list()) {
2215             HitTestResult result = m_page->mainFrame().eventHandler().hitTestResultAtPoint(request.point, HitTestRequest::ReadOnly | HitTestRequest::Active);
2216             if (result.innerNode() == input.dataListButtonElement())
2217                 info.preventTextInteraction = true;
2218         }
2219     }
2220 #endif
2221
2222 #if ENABLE(DATA_INTERACTION)
2223     info.hasSelectionAtPosition = m_page->hasSelectionAtPosition(adjustedPoint);
2224 #endif
2225     info.adjustedPointForNodeRespondingToClickEvents = adjustedPoint;
2226 }
2227
2228 void WebPage::requestPositionInformation(const InteractionInformationRequest& request)
2229 {
2230     InteractionInformationAtPosition info;
2231
2232     getPositionInformation(request, info);
2233     send(Messages::WebPageProxy::DidReceivePositionInformation(info));
2234 }
2235
2236 void WebPage::startInteractionWithElementAtPosition(const WebCore::IntPoint& point)
2237 {
2238     FloatPoint adjustedPoint;
2239     m_interactionNode = m_page->mainFrame().nodeRespondingToClickEvents(point, adjustedPoint);
2240 }
2241
2242 void WebPage::stopInteraction()
2243 {
2244     m_interactionNode = nullptr;
2245 }
2246
2247 void WebPage::performActionOnElement(uint32_t action)
2248 {
2249     if (!is<HTMLElement>(m_interactionNode.get()))
2250         return;
2251
2252     HTMLElement& element = downcast<HTMLElement>(*m_interactionNode);
2253     if (!element.renderer())
2254         return;
2255
2256     if (static_cast<SheetAction>(action) == SheetAction::Copy) {
2257         if (is<RenderImage>(*element.renderer())) {
2258             URL url;
2259             String title;
2260             if (auto* linkElement = containingLinkElement(&element)) {
2261                 url = linkElement->href();
2262                 title = linkElement->attributeWithoutSynchronization(HTMLNames::titleAttr);
2263                 if (!title.length())
2264                     title = linkElement->textContent();
2265                 title = stripLeadingAndTrailingHTMLSpaces(title);
2266             }
2267             m_interactionNode->document().frame()->editor().writeImageToPasteboard(*Pasteboard::createForCopyAndPaste(), element, url, title);
2268         } else if (element.isLink()) {
2269             m_interactionNode->document().frame()->editor().copyURL(element.document().completeURL(stripLeadingAndTrailingHTMLSpaces(element.attributeWithoutSynchronization(HTMLNames::hrefAttr))), element.textContent());
2270         }
2271     } else if (static_cast<SheetAction>(action) == SheetAction::SaveImage) {
2272         if (!is<RenderImage>(*element.renderer()))
2273             return;
2274         CachedImage* cachedImage = downcast<RenderImage>(*element.renderer()).cachedImage();
2275         if (!cachedImage)
2276             return;
2277         RefPtr<SharedBuffer> buffer = cachedImage->resourceBuffer();
2278         if (!buffer)
2279             return;
2280         uint64_t bufferSize = buffer->size();
2281         RefPtr<SharedMemory> sharedMemoryBuffer = SharedMemory::allocate(bufferSize);
2282         memcpy(sharedMemoryBuffer->data(), buffer->data(), bufferSize);
2283         SharedMemory::Handle handle;
2284         sharedMemoryBuffer->createHandle(handle, SharedMemory::Protection::ReadOnly);
2285         send(Messages::WebPageProxy::SaveImageToLibrary(handle, bufferSize));
2286     }
2287 }
2288
2289 static inline Element* nextAssistableElement(Node* startNode, Page& page, bool isForward)
2290 {
2291     if (!is<Element>(startNode))
2292         return nullptr;
2293
2294     Element* nextElement = downcast<Element>(startNode);
2295     do {
2296         nextElement = isForward
2297             ? page.focusController().nextFocusableElement(*nextElement)
2298             : page.focusController().previousFocusableElement(*nextElement);
2299     } while (nextElement && !isAssistableElement(*nextElement));
2300
2301     return nextElement;
2302 }
2303
2304 void WebPage::focusNextAssistedNode(bool isForward, CallbackID callbackID)
2305 {
2306     Element* nextElement = nextAssistableElement(m_assistedNode.get(), *m_page, isForward);
2307     m_userIsInteracting = true;
2308     if (nextElement)
2309         nextElement->focus();
2310     m_userIsInteracting = false;
2311     send(Messages::WebPageProxy::VoidCallback(callbackID));
2312 }
2313
2314 static IntRect elementRectInRootViewCoordinates(const Node& node, const Frame& frame)
2315 {
2316     auto* view = frame.view();
2317     if (!view)
2318         return { };
2319
2320     auto* renderer = node.renderer();
2321     if (!renderer)
2322         return { };
2323
2324     return view->contentsToRootView(renderer->absoluteBoundingBoxRect());
2325 }
2326
2327 void WebPage::getAssistedNodeInformation(AssistedNodeInformation& information)
2328 {
2329     layoutIfNeeded();
2330
2331     // FIXME: information.selectionRect should be set to the actual selection rect, but when this is called at focus time
2332     // we don't have a selection yet. Using the last interaction location is a reasonable approximation for now.
2333     information.selectionRect = IntRect(m_lastInteractionLocation, IntSize(1, 1));
2334
2335     if (RenderObject* renderer = m_assistedNode->renderer()) {
2336         Frame& elementFrame = m_page->focusController().focusedOrMainFrame();
2337         information.elementRect = elementRectInRootViewCoordinates(*m_assistedNode, elementFrame);
2338         information.nodeFontSize = renderer->style().fontDescription().computedSize();
2339
2340         bool inFixed = false;
2341         renderer->localToContainerPoint(FloatPoint(), nullptr, UseTransforms, &inFixed);
2342         information.insideFixedPosition = inFixed;
2343         information.isRTL = renderer->style().direction() == TextDirection::RTL;
2344
2345         FrameView* frameView = elementFrame.view();
2346         if (inFixed && elementFrame.isMainFrame() && !frameView->frame().settings().visualViewportEnabled()) {
2347             IntRect currentFixedPositionRect = frameView->customFixedPositionLayoutRect();
2348             frameView->setCustomFixedPositionLayoutRect(frameView->renderView()->documentRect());
2349             information.elementRect = frameView->contentsToRootView(renderer->absoluteBoundingBoxRect());
2350             frameView->setCustomFixedPositionLayoutRect(currentFixedPositionRect);
2351             
2352             if (!information.elementRect.contains(m_lastInteractionLocation))
2353                 information.selectionRect.setLocation(information.elementRect.location());
2354         } else {
2355             // Don't use the selection rect if interaction was outside the element rect.
2356             if (!information.elementRect.contains(m_lastInteractionLocation))
2357                 information.selectionRect = IntRect();
2358         }
2359     } else
2360         information.elementRect = IntRect();
2361
2362     information.minimumScaleFactor = minimumPageScaleFactor();
2363     information.maximumScaleFactor = maximumPageScaleFactor();
2364     information.maximumScaleFactorIgnoringAlwaysScalable = maximumPageScaleFactorIgnoringAlwaysScalable();
2365     information.allowsUserScaling = m_viewportConfiguration.allowsUserScaling();
2366     information.allowsUserScalingIgnoringAlwaysScalable = m_viewportConfiguration.allowsUserScalingIgnoringAlwaysScalable();
2367     if (auto* nextElement = nextAssistableElement(m_assistedNode.get(), *m_page, true)) {
2368         if (auto* frame = nextElement->document().frame())
2369             information.nextNodeRect = elementRectInRootViewCoordinates(*nextElement, *frame);
2370         information.hasNextNode = true;
2371     }
2372     if (auto* previousElement = nextAssistableElement(m_assistedNode.get(), *m_page, false)) {
2373         if (auto* frame = previousElement->document().frame())
2374             information.previousNodeRect = elementRectInRootViewCoordinates(*previousElement, *frame);
2375         information.hasPreviousNode = true;
2376     }
2377     information.assistedNodeIdentifier = m_currentAssistedNodeIdentifier;
2378
2379     if (is<LabelableElement>(*m_assistedNode)) {
2380         auto labels = downcast<LabelableElement>(*m_assistedNode).labels();
2381         Vector<Ref<Element>> associatedLabels;
2382         for (unsigned index = 0; index < labels->length(); ++index) {
2383             if (is<Element>(labels->item(index)) && labels->item(index)->renderer())
2384                 associatedLabels.append(downcast<Element>(*labels->item(index)));
2385         }
2386         for (auto& labelElement : associatedLabels) {
2387             auto text = labelElement->innerText();
2388             if (!text.isEmpty()) {
2389                 information.label = WTFMove(text);
2390                 break;
2391             }
2392         }
2393     }
2394
2395     if (is<Element>(m_assistedNode.get())) {
2396         auto& element = downcast<Element>(*m_assistedNode);
2397         information.title = element.title();
2398         information.ariaLabel = element.attributeWithoutSynchronization(HTMLNames::aria_labelAttr);
2399     }
2400
2401     if (is<HTMLSelectElement>(*m_assistedNode)) {
2402         HTMLSelectElement& element = downcast<HTMLSelectElement>(*m_assistedNode);
2403         information.elementType = InputType::Select;
2404         const Vector<HTMLElement*>& items = element.listItems();
2405         size_t count = items.size();
2406         int parentGroupID = 0;
2407         // The parent group ID indicates the group the option belongs to and is 0 for group elements.
2408         // If there are option elements in between groups, they are given it's own group identifier.
2409         // If a select does not have groups, all the option elements have group ID 0.
2410         for (size_t i = 0; i < count; ++i) {
2411             HTMLElement* item = items[i];
2412             if (is<HTMLOptionElement>(*item)) {
2413                 HTMLOptionElement& option = downcast<HTMLOptionElement>(*item);
2414                 information.selectOptions.append(OptionItem(option.text(), false, parentGroupID, option.selected(), option.hasAttributeWithoutSynchronization(WebCore::HTMLNames::disabledAttr)));
2415             } else if (is<HTMLOptGroupElement>(*item)) {
2416                 HTMLOptGroupElement& group = downcast<HTMLOptGroupElement>(*item);
2417                 parentGroupID++;
2418                 information.selectOptions.append(OptionItem(group.groupLabelText(), true, 0, false, group.hasAttributeWithoutSynchronization(WebCore::HTMLNames::disabledAttr)));
2419             }
2420         }
2421         information.selectedIndex = element.selectedIndex();
2422         information.isMultiSelect = element.multiple();
2423     } else if (is<HTMLTextAreaElement>(*m_assistedNode)) {
2424         HTMLTextAreaElement& element = downcast<HTMLTextAreaElement>(*m_assistedNode);
2425         information.autocapitalizeType = element.autocapitalizeType();
2426         information.isAutocorrect = element.shouldAutocorrect();
2427         information.elementType = InputType::TextArea;
2428         information.isReadOnly = element.isReadOnly();
2429         information.value = element.value();
2430         information.autofillFieldName = WebCore::toAutofillFieldName(element.autofillData().fieldName);
2431         information.placeholder = element.attributeWithoutSynchronization(HTMLNames::placeholderAttr);
2432         information.inputMode = element.canonicalInputMode();
2433     } else if (is<HTMLInputElement>(*m_assistedNode)) {
2434         HTMLInputElement& element = downcast<HTMLInputElement>(*m_assistedNode);
2435         HTMLFormElement* form = element.form();
2436         if (form)
2437             information.formAction = form->getURLAttribute(WebCore::HTMLNames::actionAttr);
2438         if (auto autofillElements = WebCore::AutofillElements::computeAutofillElements(element)) {
2439             information.acceptsAutofilledLoginCredentials = true;
2440             information.isAutofillableUsernameField = autofillElements->username() == m_assistedNode;
2441         }
2442         information.representingPageURL = element.document().urlForBindings();
2443         information.autocapitalizeType = element.autocapitalizeType();
2444         information.isAutocorrect = element.shouldAutocorrect();
2445         information.placeholder = element.attributeWithoutSynchronization(HTMLNames::placeholderAttr);
2446         if (element.isPasswordField())
2447             information.elementType = InputType::Password;
2448         else if (element.isSearchField())
2449             information.elementType = InputType::Search;
2450         else if (element.isEmailField())
2451             information.elementType = InputType::Email;
2452         else if (element.isTelephoneField())
2453             information.elementType = InputType::Phone;
2454         else if (element.isNumberField())
2455             information.elementType = element.getAttribute("pattern") == "\\d*" || element.getAttribute("pattern") == "[0-9]*" ? InputType::NumberPad : InputType::Number;
2456         else if (element.isDateTimeLocalField())
2457             information.elementType = InputType::DateTimeLocal;
2458         else if (element.isDateField())
2459             information.elementType = InputType::Date;
2460         else if (element.isDateTimeField())
2461             information.elementType = InputType::DateTime;
2462         else if (element.isTimeField())
2463             information.elementType = InputType::Time;
2464         else if (element.isWeekField())
2465             information.elementType = InputType::Week;
2466         else if (element.isMonthField())
2467             information.elementType = InputType::Month;
2468         else if (element.isURLField())
2469             information.elementType = InputType::URL;
2470         else if (element.isText()) {
2471             const AtomicString& pattern = element.attributeWithoutSynchronization(HTMLNames::patternAttr);
2472             if (pattern == "\\d*" || pattern == "[0-9]*")
2473                 information.elementType = InputType::NumberPad;
2474             else {
2475                 information.elementType = InputType::Text;
2476                 if (!information.formAction.isEmpty()
2477                     && (element.getNameAttribute().contains("search") || element.getIdAttribute().contains("search") || element.attributeWithoutSynchronization(HTMLNames::titleAttr).contains("search")))
2478                     information.elementType = InputType::Search;
2479             }
2480         }
2481 #if ENABLE(INPUT_TYPE_COLOR)
2482         else if (element.isColorControl()) {
2483             information.elementType = InputType::Color;
2484 #if ENABLE(DATALIST_ELEMENT)
2485             information.suggestedColors = element.suggestedColors();
2486 #endif
2487         }
2488 #endif
2489
2490 #if ENABLE(DATALIST_ELEMENT)
2491         information.hasSuggestions = !!element.list();
2492 #endif
2493         information.inputMode = element.canonicalInputMode();
2494         information.isReadOnly = element.isReadOnly();
2495         information.value = element.value();
2496         information.valueAsNumber = element.valueAsNumber();
2497         information.autofillFieldName = WebCore::toAutofillFieldName(element.autofillData().fieldName);
2498     } else if (m_assistedNode->hasEditableStyle()) {
2499         information.elementType = InputType::ContentEditable;
2500         if (is<HTMLElement>(*m_assistedNode)) {
2501             auto& assistedElement = downcast<HTMLElement>(*m_assistedNode);
2502             information.isAutocorrect = assistedElement.shouldAutocorrect();
2503             information.autocapitalizeType = assistedElement.autocapitalizeType();
2504             information.inputMode = assistedElement.canonicalInputMode();
2505         } else {
2506             information.isAutocorrect = true;
2507             information.autocapitalizeType = AutocapitalizeTypeDefault;
2508         }
2509         information.isReadOnly = false;
2510     }
2511 }
2512
2513 void WebPage::autofillLoginCredentials(const String& username, const String& password)
2514 {
2515     if (is<HTMLInputElement>(m_assistedNode.get())) {
2516         if (auto autofillElements = AutofillElements::computeAutofillElements(downcast<HTMLInputElement>(*m_assistedNode)))
2517             autofillElements->autofill(username, password);
2518     }
2519 }
2520
2521 // WebCore stores the page scale factor as float instead of double. When we get a scale from WebCore,
2522 // we need to ignore differences that are within a small rounding error on floats.
2523 static inline bool areEssentiallyEqualAsFloat(float a, float b)
2524 {
2525     return WTF::areEssentiallyEqual(a, b);
2526 }
2527
2528 void WebPage::setViewportConfigurationViewLayoutSize(const FloatSize& size, double scaleFactor)
2529 {
2530     LOG_WITH_STREAM(VisibleRects, stream << "WebPage " << m_pageID << " setViewportConfigurationViewLayoutSize " << size << " scaleFactor " << scaleFactor);
2531
2532     ZoomToInitialScale shouldZoomToInitialScale = ZoomToInitialScale::No;
2533     if (m_viewportConfiguration.layoutSizeScaleFactor() != scaleFactor && areEssentiallyEqualAsFloat(m_viewportConfiguration.initialScale(), pageScaleFactor()))
2534         shouldZoomToInitialScale = ZoomToInitialScale::Yes;
2535
2536     if (m_viewportConfiguration.setViewLayoutSize(size, scaleFactor))
2537         viewportConfigurationChanged(shouldZoomToInitialScale);
2538 }
2539
2540 void WebPage::setMaximumUnobscuredSize(const FloatSize& maximumUnobscuredSize)
2541 {
2542     m_maximumUnobscuredSize = maximumUnobscuredSize;
2543     updateViewportSizeForCSSViewportUnits();
2544 }
2545
2546 void WebPage::setDeviceOrientation(int32_t deviceOrientation)
2547 {
2548     if (deviceOrientation == m_deviceOrientation)
2549         return;
2550     m_deviceOrientation = deviceOrientation;
2551     m_page->mainFrame().orientationChanged();
2552 }
2553
2554 void WebPage::setOverrideViewportArguments(const std::optional<WebCore::ViewportArguments>& arguments)
2555 {
2556     if (auto* document = m_page->mainFrame().document())
2557         document->setOverrideViewportArguments(arguments);
2558 }
2559
2560 void WebPage::resetTextAutosizing()
2561 {
2562     for (Frame* frame = &m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
2563         Document* document = frame->document();
2564         if (!document || !document->renderView())
2565             continue;
2566         document->renderView()->resetTextAutosizing();
2567     }
2568 }
2569
2570 void WebPage::dynamicViewportSizeUpdate(const FloatSize& viewLayoutSize, const WebCore::FloatSize& maximumUnobscuredSize, const FloatRect& targetExposedContentRect, const FloatRect& targetUnobscuredRect, const WebCore::FloatRect& targetUnobscuredRectInScrollViewCoordinates, const WebCore::FloatBoxExtent& targetUnobscuredSafeAreaInsets, double targetScale, int32_t deviceOrientation, DynamicViewportSizeUpdateID dynamicViewportSizeUpdateID)
2571 {
2572     SetForScope<bool> dynamicSizeUpdateGuard(m_inDynamicSizeUpdate, true);
2573     // FIXME: this does not handle the cases where the content would change the content size or scroll position from JavaScript.
2574     // To handle those cases, we would need to redo this computation on every change until the next visible content rect update.
2575     LOG_WITH_STREAM(VisibleRects, stream << "\nWebPage::dynamicViewportSizeUpdate - viewLayoutSize " << viewLayoutSize << " targetUnobscuredRect " << targetUnobscuredRect << " targetExposedContentRect " << targetExposedContentRect << " targetScale " << targetScale);
2576
2577     FrameView& frameView = *m_page->mainFrame().view();
2578     IntSize oldContentSize = frameView.contentsSize();
2579     float oldPageScaleFactor = m_page->pageScaleFactor();
2580
2581     m_dynamicSizeUpdateHistory.add(std::make_pair(oldContentSize, oldPageScaleFactor), frameView.scrollPosition());
2582
2583     RefPtr<Node> oldNodeAtCenter;
2584     double visibleHorizontalFraction = 1;
2585     float relativeHorizontalPositionInNodeAtCenter = 0;
2586     float relativeVerticalPositionInNodeAtCenter = 0;
2587     {
2588         visibleHorizontalFraction = frameView.unobscuredContentSize().width() / oldContentSize.width();
2589         IntPoint unobscuredContentRectCenter = frameView.unobscuredContentRect().center();
2590
2591         HitTestResult hitTestResult = HitTestResult(unobscuredContentRectCenter);
2592
2593         if (RenderView* mainFrameRenderView = frameView.renderView())
2594             mainFrameRenderView->hitTest(HitTestRequest(), hitTestResult);
2595
2596         if (Node* node = hitTestResult.innerNode()) {
2597             if (RenderObject* renderer = node->renderer()) {
2598                 FrameView& containingView = *node->document().frame()->view();
2599                 FloatRect boundingBox = containingView.contentsToRootView(renderer->absoluteBoundingBoxRect(true));
2600                 relativeHorizontalPositionInNodeAtCenter = (unobscuredContentRectCenter.x() - boundingBox.x()) / boundingBox.width();
2601                 relativeVerticalPositionInNodeAtCenter = (unobscuredContentRectCenter.y() - boundingBox.y()) / boundingBox.height();
2602                 oldNodeAtCenter = node;
2603             }
2604         }
2605     }
2606
2607     LOG_WITH_STREAM(VisibleRects, stream << "WebPage::dynamicViewportSizeUpdate setting view layout size to " << viewLayoutSize);
2608     m_viewportConfiguration.setViewLayoutSize(viewLayoutSize);
2609     IntSize newLayoutSize = m_viewportConfiguration.layoutSize();
2610
2611     if (setFixedLayoutSize(newLayoutSize))
2612         resetTextAutosizing();
2613
2614     setMaximumUnobscuredSize(maximumUnobscuredSize);
2615     m_page->setUnobscuredSafeAreaInsets(targetUnobscuredSafeAreaInsets);
2616
2617     frameView.updateLayoutAndStyleIfNeededRecursive();
2618
2619     IntSize newContentSize = frameView.contentsSize();
2620
2621     double scale = scaleAfterViewportWidthChange(targetScale, m_userHasChangedPageScaleFactor, m_viewportConfiguration, targetUnobscuredRectInScrollViewCoordinates.width(), newContentSize, oldContentSize, visibleHorizontalFraction);
2622     FloatRect newUnobscuredContentRect = targetUnobscuredRect;
2623     FloatRect newExposedContentRect = targetExposedContentRect;
2624
2625     bool scaleChanged = !areEssentiallyEqualAsFloat(scale, targetScale);
2626     if (scaleChanged) {
2627         // The target scale the UI is using cannot be reached by the content. We need to compute new targets based
2628         // on the viewport constraint and report everything back to the UIProcess.
2629
2630         // 1) Compute a new unobscured rect centered around the original one.
2631         double scaleDifference = targetScale / scale;
2632         double newUnobscuredRectWidth = targetUnobscuredRect.width() * scaleDifference;
2633         double newUnobscuredRectHeight = targetUnobscuredRect.height() * scaleDifference;
2634         double newUnobscuredRectX = targetUnobscuredRect.x() - (newUnobscuredRectWidth - targetUnobscuredRect.width()) / 2;
2635         double newUnobscuredRectY = targetUnobscuredRect.y() - (newUnobscuredRectHeight - targetUnobscuredRect.height()) / 2;
2636         newUnobscuredContentRect = FloatRect(newUnobscuredRectX, newUnobscuredRectY, newUnobscuredRectWidth, newUnobscuredRectHeight);
2637
2638         // 2) Extend our new unobscuredRect by the obscured margins to get a new exposed rect.
2639         double obscuredTopMargin = (targetUnobscuredRect.y() - targetExposedContentRect.y()) * scaleDifference;
2640         double obscuredLeftMargin = (targetUnobscuredRect.x() - targetExposedContentRect.x()) * scaleDifference;
2641         double obscuredBottomMargin = (targetExposedContentRect.maxY() - targetUnobscuredRect.maxY()) * scaleDifference;
2642         double obscuredRightMargin = (targetExposedContentRect.maxX() - targetUnobscuredRect.maxX()) * scaleDifference;
2643         newExposedContentRect = FloatRect(newUnobscuredRectX - obscuredLeftMargin,
2644                                           newUnobscuredRectY - obscuredTopMargin,
2645                                           newUnobscuredRectWidth + obscuredLeftMargin + obscuredRightMargin,
2646                                           newUnobscuredRectHeight + obscuredTopMargin + obscuredBottomMargin);
2647     }
2648
2649     if (oldContentSize != newContentSize || scaleChanged) {
2650         // Snap the new unobscured rect back into the content rect.
2651         newUnobscuredContentRect.setWidth(std::min(static_cast<float>(newContentSize.width()), newUnobscuredContentRect.width()));
2652         newUnobscuredContentRect.setHeight(std::min(static_cast<float>(newContentSize.height()), newUnobscuredContentRect.height()));
2653
2654         bool positionWasRestoredFromSizeUpdateHistory = false;
2655         const auto& previousPosition = m_dynamicSizeUpdateHistory.find(std::pair<IntSize, float>(newContentSize, scale));
2656         if (previousPosition != m_dynamicSizeUpdateHistory.end()) {
2657             IntPoint restoredPosition = previousPosition->value;
2658             FloatPoint deltaPosition(restoredPosition.x() - newUnobscuredContentRect.x(), restoredPosition.y() - newUnobscuredContentRect.y());
2659             newUnobscuredContentRect.moveBy(deltaPosition);
2660             newExposedContentRect.moveBy(deltaPosition);
2661             positionWasRestoredFromSizeUpdateHistory = true;
2662         } else if (oldContentSize != newContentSize) {
2663             FloatPoint newRelativeContentCenter;
2664
2665             if (RenderObject* renderer = oldNodeAtCenter ? oldNodeAtCenter->renderer() : nullptr) {
2666                 FrameView& containingView = *oldNodeAtCenter->document().frame()->view();
2667                 FloatRect newBoundingBox = containingView.contentsToRootView(renderer->absoluteBoundingBoxRect(true));
2668                 newRelativeContentCenter = FloatPoint(newBoundingBox.x() + relativeHorizontalPositionInNodeAtCenter * newBoundingBox.width(), newBoundingBox.y() + relativeVerticalPositionInNodeAtCenter * newBoundingBox.height());
2669             } else
2670                 newRelativeContentCenter = relativeCenterAfterContentSizeChange(targetUnobscuredRect, oldContentSize, newContentSize);
2671
2672             FloatPoint newUnobscuredContentRectCenter = newUnobscuredContentRect.center();
2673             FloatPoint positionDelta(newRelativeContentCenter.x() - newUnobscuredContentRectCenter.x(), newRelativeContentCenter.y() - newUnobscuredContentRectCenter.y());
2674             newUnobscuredContentRect.moveBy(positionDelta);
2675             newExposedContentRect.moveBy(positionDelta);
2676         }
2677
2678         // Make the top/bottom edges "sticky" within 1 pixel.
2679         if (!positionWasRestoredFromSizeUpdateHistory) {
2680             if (targetUnobscuredRect.maxY() > oldContentSize.height() - 1) {
2681                 float bottomVerticalPosition = newContentSize.height() - newUnobscuredContentRect.height();
2682                 newUnobscuredContentRect.setY(bottomVerticalPosition);
2683                 newExposedContentRect.setY(bottomVerticalPosition);
2684             }
2685             if (targetUnobscuredRect.y() < 1) {
2686                 newUnobscuredContentRect.setY(0);
2687                 newExposedContentRect.setY(0);
2688             }
2689
2690             bool likelyResponsiveDesignViewport = newLayoutSize.width() == viewLayoutSize.width() && areEssentiallyEqualAsFloat(scale, 1);
2691             bool contentBleedsOutsideLayoutWidth = newContentSize.width() > newLayoutSize.width();
2692             bool originalScrollPositionWasOnTheLeftEdge = targetUnobscuredRect.x() <= 0;
2693             if (likelyResponsiveDesignViewport && contentBleedsOutsideLayoutWidth && originalScrollPositionWasOnTheLeftEdge) {
2694                 // This is a special heuristics for "responsive" design with odd layout. It is quite common for responsive design
2695                 // to have content "bleeding" outside of the minimal layout width, usually from an image or table larger than expected.
2696                 // In those cases, the design usually does not adapt to the new width and remain at the newLayoutSize except for the
2697                 // large boxes.
2698                 // It is worth revisiting this special case as web developers get better with responsive design.
2699                 newExposedContentRect.setX(0);
2700                 newUnobscuredContentRect.setX(0);
2701             }
2702         }
2703
2704         float horizontalAdjustment = 0;
2705         if (newUnobscuredContentRect.maxX() > newContentSize.width())
2706             horizontalAdjustment -= newUnobscuredContentRect.maxX() - newContentSize.width();
2707         float verticalAdjustment = 0;
2708         if (newUnobscuredContentRect.maxY() > newContentSize.height())
2709             verticalAdjustment -= newUnobscuredContentRect.maxY() - newContentSize.height();
2710         if (newUnobscuredContentRect.x() < 0)
2711             horizontalAdjustment += - newUnobscuredContentRect.x();
2712         if (newUnobscuredContentRect.y() < 0)
2713             verticalAdjustment += - newUnobscuredContentRect.y();
2714
2715         FloatPoint adjustmentDelta(horizontalAdjustment, verticalAdjustment);
2716         newUnobscuredContentRect.moveBy(adjustmentDelta);
2717         newExposedContentRect.moveBy(adjustmentDelta);
2718     }
2719
2720     frameView.setScrollVelocity(0, 0, 0, MonotonicTime::now());
2721
2722     IntPoint roundedUnobscuredContentRectPosition = roundedIntPoint(newUnobscuredContentRect.location());
2723     frameView.setUnobscuredContentSize(newUnobscuredContentRect.size());
2724     m_drawingArea->setExposedContentRect(newExposedContentRect);
2725
2726     scalePage(scale, roundedUnobscuredContentRectPosition);
2727
2728     frameView.updateLayoutAndStyleIfNeededRecursive();
2729
2730     auto& settings = frameView.frame().settings();
2731     if (settings.visualViewportEnabled()) {
2732         LayoutRect documentRect = IntRect(frameView.scrollOrigin(), frameView.contentsSize());
2733         auto layoutViewportSize = FrameView::expandedLayoutViewportSize(frameView.baseLayoutViewportSize(), LayoutSize(documentRect.size()), settings.layoutViewportHeightExpansionFactor());
2734         LayoutRect layoutViewportRect = FrameView::computeUpdatedLayoutViewportRect(frameView.layoutViewportRect(), documentRect, LayoutSize(newUnobscuredContentRect.size()), LayoutRect(newUnobscuredContentRect), layoutViewportSize, frameView.minStableLayoutViewportOrigin(), frameView.maxStableLayoutViewportOrigin(), FrameView::LayoutViewportConstraint::ConstrainedToDocumentRect);
2735         frameView.setLayoutViewportOverrideRect(layoutViewportRect);
2736     } else {
2737         IntRect fixedPositionLayoutRect = enclosingIntRect(frameView.viewportConstrainedObjectsRect());
2738         frameView.setCustomFixedPositionLayoutRect(fixedPositionLayoutRect);
2739     }
2740
2741     frameView.setCustomSizeForResizeEvent(expandedIntSize(targetUnobscuredRectInScrollViewCoordinates.size()));
2742     setDeviceOrientation(deviceOrientation);
2743     frameView.setScrollOffset(roundedUnobscuredContentRectPosition);
2744
2745     m_drawingArea->scheduleCompositingLayerFlush();
2746
2747     m_pendingDynamicViewportSizeUpdateID = dynamicViewportSizeUpdateID;
2748 }
2749
2750 void WebPage::resetViewportDefaultConfiguration(WebFrame* frame, bool hasMobileDocType)
2751 {
2752     LOG_WITH_STREAM(VisibleRects, stream << "WebPage " << m_pageID << " resetViewportDefaultConfiguration");
2753     if (m_useTestingViewportConfiguration) {
2754         m_viewportConfiguration.setDefaultConfiguration(ViewportConfiguration::testingParameters());
2755         return;
2756     }
2757
2758     auto parametersForStandardFrame = [&] {
2759         if (m_page->settings().shouldIgnoreMetaViewport())
2760             return ViewportConfiguration::nativeWebpageParameters();
2761
2762         return ViewportConfiguration::webpageParameters();
2763     };
2764
2765     if (!frame) {
2766         m_viewportConfiguration.setDefaultConfiguration(parametersForStandardFrame());
2767         return;
2768     }
2769
2770     if (hasMobileDocType) {
2771         m_viewportConfiguration.setDefaultConfiguration(ViewportConfiguration::xhtmlMobileParameters());
2772         return;
2773     }
2774
2775     Document* document = frame->coreFrame()->document();
2776     if (document->isImageDocument())
2777         m_viewportConfiguration.setDefaultConfiguration(ViewportConfiguration::imageDocumentParameters());
2778     else if (document->isTextDocument())
2779         m_viewportConfiguration.setDefaultConfiguration(ViewportConfiguration::textDocumentParameters());
2780     else
2781         m_viewportConfiguration.setDefaultConfiguration(parametersForStandardFrame());
2782 }
2783
2784 void WebPage::viewportConfigurationChanged(ZoomToInitialScale zoomToInitialScale)
2785 {
2786     if (setFixedLayoutSize(m_viewportConfiguration.layoutSize()))
2787         resetTextAutosizing();
2788
2789     double initialScale = m_viewportConfiguration.initialScale();
2790     double scale;
2791     if (m_userHasChangedPageScaleFactor && zoomToInitialScale == ZoomToInitialScale::No)
2792         scale = std::max(std::min(pageScaleFactor(), m_viewportConfiguration.maximumScale()), m_viewportConfiguration.minimumScale());
2793     else
2794         scale = initialScale;
2795
2796     LOG_WITH_STREAM(VisibleRects, stream << "WebPage " << m_pageID << " viewportConfigurationChanged - setting zoomedOutPageScaleFactor to " << m_viewportConfiguration.minimumScale() << " and scale to " << scale);
2797
2798     m_page->setZoomedOutPageScaleFactor(m_viewportConfiguration.minimumScale());
2799
2800     updateViewportSizeForCSSViewportUnits();
2801
2802     FrameView& frameView = *mainFrameView();
2803     IntPoint scrollPosition = frameView.scrollPosition();
2804     if (!m_hasReceivedVisibleContentRectsAfterDidCommitLoad) {
2805         FloatSize minimumLayoutSizeInScrollViewCoordinates = m_viewportConfiguration.viewLayoutSize();
2806         minimumLayoutSizeInScrollViewCoordinates.scale(1 / scale);
2807         IntSize minimumLayoutSizeInDocumentCoordinates = roundedIntSize(minimumLayoutSizeInScrollViewCoordinates);
2808         frameView.setUnobscuredContentSize(minimumLayoutSizeInDocumentCoordinates);
2809         frameView.setScrollVelocity(0, 0, 0, MonotonicTime::now());
2810
2811         // FIXME: We could send down the obscured margins to find a better exposed rect and unobscured rect.
2812         // It is not a big deal at the moment because the tile coverage will always extend past the obscured bottom inset.
2813         m_drawingArea->setExposedContentRect(FloatRect(scrollPosition, minimumLayoutSizeInDocumentCoordinates));
2814     }
2815     scalePage(scale, scrollPosition);
2816     
2817     if (!m_hasReceivedVisibleContentRectsAfterDidCommitLoad) {
2818         // This takes scale into account, so do after the scale change.
2819         frameView.setCustomFixedPositionLayoutRect(enclosingIntRect(frameView.viewportConstrainedObjectsRect()));
2820
2821         frameView.setCustomSizeForResizeEvent(expandedIntSize(m_viewportConfiguration.minimumLayoutSize()));
2822     }
2823 }
2824
2825 void WebPage::updateViewportSizeForCSSViewportUnits()
2826 {
2827     FloatSize largestUnobscuredSize = m_maximumUnobscuredSize;
2828     if (largestUnobscuredSize.isEmpty())
2829         largestUnobscuredSize = m_viewportConfiguration.viewLayoutSize();
2830
2831     FrameView& frameView = *mainFrameView();
2832     largestUnobscuredSize.scale(1 / m_viewportConfiguration.initialScaleIgnoringContentSize());
2833     frameView.setViewportSizeForCSSViewportUnits(roundedIntSize(largestUnobscuredSize));
2834 }
2835
2836 void WebPage::applicationWillResignActive()
2837 {
2838     [[NSNotificationCenter defaultCenter] postNotificationName:WebUIApplicationWillResignActiveNotification object:nil];
2839     if (m_page)
2840         m_page->applicationWillResignActive();
2841 }
2842
2843 void WebPage::applicationDidEnterBackground(bool isSuspendedUnderLock)
2844 {
2845     [[NSNotificationCenter defaultCenter] postNotificationName:WebUIApplicationDidEnterBackgroundNotification object:nil userInfo:@{@"isSuspendedUnderLock": [NSNumber numberWithBool:isSuspendedUnderLock]}];
2846
2847     m_isSuspendedUnderLock = isSuspendedUnderLock;
2848     setLayerTreeStateIsFrozen(true);
2849
2850     if (m_page)
2851         m_page->applicationDidEnterBackground();
2852 }
2853
2854 void WebPage::applicationDidFinishSnapshottingAfterEnteringBackground()
2855 {
2856     markLayersVolatile();
2857 }
2858
2859 void WebPage::applicationWillEnterForeground(bool isSuspendedUnderLock)
2860 {
2861     m_isSuspendedUnderLock = false;
2862     cancelMarkLayersVolatile();
2863     setLayerTreeStateIsFrozen(false);
2864
2865     [[NSNotificationCenter defaultCenter] postNotificationName:WebUIApplicationWillEnterForegroundNotification object:nil userInfo:@{@"isSuspendedUnderLock": @(isSuspendedUnderLock)}];
2866
2867     if (m_page)
2868         m_page->applicationWillEnterForeground();
2869 }
2870
2871 void WebPage::applicationDidBecomeActive()
2872 {
2873     [[NSNotificationCenter defaultCenter] postNotificationName:WebUIApplicationDidBecomeActiveNotification object:nil];
2874     if (m_page)
2875         m_page->applicationDidBecomeActive();
2876 }
2877
2878 static inline void adjustVelocityDataForBoundedScale(double& horizontalVelocity, double& verticalVelocity, double& scaleChangeRate, double exposedRectScale, double minimumScale, double maximumScale)
2879 {
2880     if (scaleChangeRate) {
2881         horizontalVelocity = 0;
2882         verticalVelocity = 0;
2883     }
2884
2885     if (exposedRectScale >= maximumScale || exposedRectScale <= minimumScale)
2886         scaleChangeRate = 0;
2887 }
2888
2889 std::optional<float> WebPage::scaleFromUIProcess(const VisibleContentRectUpdateInfo& visibleContentRectUpdateInfo) const
2890 {
2891     auto transactionIDForLastScaleFromUIProcess = visibleContentRectUpdateInfo.lastLayerTreeTransactionID();
2892     if (m_lastTransactionIDWithScaleChange > transactionIDForLastScaleFromUIProcess)
2893         return std::nullopt;
2894
2895     float scaleFromUIProcess = visibleContentRectUpdateInfo.scale();
2896     float currentScale = m_page->pageScaleFactor();
2897
2898     double scaleNoiseThreshold = 0.005;
2899     if (!m_isInStableState && fabs(scaleFromUIProcess - currentScale) < scaleNoiseThreshold) {
2900         // Tiny changes of scale during interactive zoom cause content to jump by one pixel, creating
2901         // visual noise. We filter those useless updates.
2902         scaleFromUIProcess = currentScale;
2903     }
2904     
2905     scaleFromUIProcess = std::min<float>(m_viewportConfiguration.maximumScale(), std::max<float>(m_viewportConfiguration.minimumScale(), scaleFromUIProcess));
2906     if (areEssentiallyEqualAsFloat(currentScale, scaleFromUIProcess))
2907         return std::nullopt;
2908
2909     return scaleFromUIProcess;
2910 }
2911
2912 static bool selectionIsInsideFixedPositionContainer(Frame& frame)
2913 {
2914     auto& selection = frame.selection().selection();
2915     if (selection.isNone())
2916         return false;
2917
2918     bool isInsideFixedPosition = false;
2919     if (selection.isCaret()) {
2920         frame.selection().absoluteCaretBounds(&isInsideFixedPosition);
2921         return isInsideFixedPosition;
2922     }
2923
2924     selection.visibleStart().absoluteCaretBounds(&isInsideFixedPosition);
2925     if (isInsideFixedPosition)
2926         return true;
2927
2928     selection.visibleEnd().absoluteCaretBounds(&isInsideFixedPosition);
2929     return isInsideFixedPosition;
2930 }
2931
2932 void WebPage::updateVisibleContentRects(const VisibleContentRectUpdateInfo& visibleContentRectUpdateInfo, MonotonicTime oldestTimestamp)
2933 {
2934     LOG_WITH_STREAM(VisibleRects, stream << "\nWebPage " << m_pageID << " updateVisibleContentRects " << visibleContentRectUpdateInfo);
2935
2936     // Skip any VisibleContentRectUpdate that have been queued before DidCommitLoad suppresses the updates in the UIProcess.
2937     if (visibleContentRectUpdateInfo.lastLayerTreeTransactionID() < m_mainFrame->firstLayerTreeTransactionIDAfterDidCommitLoad() && !visibleContentRectUpdateInfo.isFirstUpdateForNewViewSize())
2938         return;
2939
2940     m_hasReceivedVisibleContentRectsAfterDidCommitLoad = true;
2941     m_isInStableState = visibleContentRectUpdateInfo.inStableState();
2942
2943     auto scaleFromUIProcess = this->scaleFromUIProcess(visibleContentRectUpdateInfo);
2944
2945     // Skip progressively redrawing tiles if pinch-zooming while the system is under memory pressure.
2946     if (scaleFromUIProcess && !m_isInStableState && MemoryPressureHandler::singleton().isUnderMemoryPressure())
2947         return;
2948
2949     if (m_isInStableState)
2950         m_hasStablePageScaleFactor = true;
2951     else {
2952         if (!m_oldestNonStableUpdateVisibleContentRectsTimestamp)
2953             m_oldestNonStableUpdateVisibleContentRectsTimestamp = oldestTimestamp;
2954     }
2955
2956     float scaleToUse = scaleFromUIProcess.value_or(m_page->pageScaleFactor());
2957     FloatRect exposedContentRect = visibleContentRectUpdateInfo.exposedContentRect();
2958     FloatRect adjustedExposedContentRect = adjustExposedRectForNewScale(exposedContentRect, visibleContentRectUpdateInfo.scale(), scaleToUse);
2959     m_drawingArea->setExposedContentRect(adjustedExposedContentRect);
2960
2961     IntPoint scrollPosition = roundedIntPoint(visibleContentRectUpdateInfo.unobscuredContentRect().location());
2962
2963     bool hasSetPageScale = false;
2964     if (scaleFromUIProcess) {
2965         m_scaleWasSetByUIProcess = true;
2966         m_hasStablePageScaleFactor = m_isInStableState;
2967
2968         m_dynamicSizeUpdateHistory.clear();
2969
2970         m_page->setPageScaleFactor(scaleFromUIProcess.value(), scrollPosition, m_isInStableState);
2971         hasSetPageScale = true;
2972         send(Messages::WebPageProxy::PageScaleFactorDidChange(scaleFromUIProcess.value()));
2973     }
2974     
2975     if (!hasSetPageScale && m_isInStableState) {
2976         m_page->setPageScaleFactor(scaleToUse, scrollPosition, true);
2977         hasSetPageScale = true;
2978     }
2979
2980     auto& frame = m_page->mainFrame();
2981     FrameView& frameView = *frame.view();
2982     if (scrollPosition != frameView.scrollPosition())
2983         m_dynamicSizeUpdateHistory.clear();
2984
2985     if (m_viewportConfiguration.setCanIgnoreScalingConstraints(m_ignoreViewportScalingConstraints && visibleContentRectUpdateInfo.allowShrinkToFit()))
2986         viewportConfigurationChanged();
2987
2988     frameView.setUnobscuredContentSize(visibleContentRectUpdateInfo.unobscuredContentRect().size());
2989     m_page->setObscuredInsets(visibleContentRectUpdateInfo.obscuredInsets());
2990     m_page->setUnobscuredSafeAreaInsets(visibleContentRectUpdateInfo.unobscuredSafeAreaInsets());
2991     m_page->setEnclosedInScrollableAncestorView(visibleContentRectUpdateInfo.enclosedInScrollableAncestorView());
2992
2993     double horizontalVelocity = visibleContentRectUpdateInfo.horizontalVelocity();
2994     double verticalVelocity = visibleContentRectUpdateInfo.verticalVelocity();
2995     double scaleChangeRate = visibleContentRectUpdateInfo.scaleChangeRate();
2996     adjustVelocityDataForBoundedScale(horizontalVelocity, verticalVelocity, scaleChangeRate, visibleContentRectUpdateInfo.scale(), m_viewportConfiguration.minimumScale(), m_viewportConfiguration.maximumScale());
2997
2998     frameView.setScrollVelocity(horizontalVelocity, verticalVelocity, scaleChangeRate, visibleContentRectUpdateInfo.timestamp());
2999
3000     if (m_isInStableState) {
3001         if (frameView.frame().settings().visualViewportEnabled()) {
3002             if (visibleContentRectUpdateInfo.unobscuredContentRect() != visibleContentRectUpdateInfo.unobscuredContentRectRespectingInputViewBounds())
3003                 frameView.setVisualViewportOverrideRect(LayoutRect(visibleContentRectUpdateInfo.unobscuredContentRectRespectingInputViewBounds()));
3004             else
3005                 frameView.setVisualViewportOverrideRect(std::nullopt);
3006
3007             LOG_WITH_STREAM(VisibleRects, stream << "WebPage::updateVisibleContentRects - setLayoutViewportOverrideRect " << visibleContentRectUpdateInfo.customFixedPositionRect());
3008             frameView.setLayoutViewportOverrideRect(LayoutRect(visibleContentRectUpdateInfo.customFixedPositionRect()));
3009             if (selectionIsInsideFixedPositionContainer(frame)) {
3010                 // Ensure that the next layer tree commit contains up-to-date caret/selection rects.
3011                 frameView.frame().selection().setCaretRectNeedsUpdate();
3012                 sendPartialEditorStateAndSchedulePostLayoutUpdate();
3013             }
3014         } else
3015             frameView.setCustomFixedPositionLayoutRect(enclosingIntRect(visibleContentRectUpdateInfo.customFixedPositionRect()));
3016     }
3017
3018     if (!visibleContentRectUpdateInfo.isChangingObscuredInsetsInteractively())
3019         frameView.setCustomSizeForResizeEvent(expandedIntSize(visibleContentRectUpdateInfo.unobscuredRectInScrollViewCoordinates().size()));
3020
3021     if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) {
3022         ViewportRectStability viewportStability = ViewportRectStability::Stable;
3023         ScrollingLayerPositionAction layerAction = ScrollingLayerPositionAction::Sync;
3024         
3025         if (visibleContentRectUpdateInfo.isChangingObscuredInsetsInteractively()) {
3026             viewportStability = ViewportRectStability::ChangingObscuredInsetsInteractively;
3027             layerAction = ScrollingLayerPositionAction::SetApproximate;
3028         } else if (!m_isInStableState) {
3029             viewportStability = ViewportRectStability::Unstable;
3030             layerAction = ScrollingLayerPositionAction::SetApproximate;
3031         }
3032         scrollingCoordinator->reconcileScrollingState(frameView, scrollPosition, visibleContentRectUpdateInfo.customFixedPositionRect(), false, viewportStability, layerAction);
3033     }
3034 }
3035
3036 void WebPage::willStartUserTriggeredZooming()
3037 {
3038     m_page->diagnosticLoggingClient().logDiagnosticMessage(DiagnosticLoggingKeys::webViewKey(), DiagnosticLoggingKeys::userZoomActionKey(), ShouldSample::No);
3039     m_userHasChangedPageScaleFactor = true;
3040 }
3041
3042 #if ENABLE(IOS_TOUCH_EVENTS)
3043 void WebPage::dispatchAsynchronousTouchEvents(const Vector<WebTouchEvent, 1>& queue)
3044 {
3045     bool ignored;
3046     for (const WebTouchEvent& event : queue)
3047         dispatchTouchEvent(event, ignored);
3048 }
3049 #endif
3050
3051 void WebPage::computePagesForPrintingAndDrawToPDF(uint64_t frameID, const PrintInfo& printInfo, CallbackID callbackID, Messages::WebPage::ComputePagesForPrintingAndDrawToPDF::DelayedReply&& reply)
3052 {
3053     if (printInfo.snapshotFirstPage) {
3054         reply(1);
3055         IntSize snapshotSize { FloatSize { printInfo.availablePaperWidth, printInfo.availablePaperHeight } };
3056         IntRect snapshotRect { {0, 0}, snapshotSize };
3057         auto pdfData = pdfSnapshotAtSize(snapshotRect, snapshotSize, 0);
3058         send(Messages::WebPageProxy::DrawToPDFCallback(IPC::DataReference(CFDataGetBytePtr(pdfData.get()), CFDataGetLength(pdfData.get())), callbackID));
3059         return;
3060     }
3061
3062     Vector<WebCore::IntRect> pageRects;
3063     double totalScaleFactor;
3064     computePagesForPrintingImpl(frameID, printInfo, pageRects, totalScaleFactor);
3065
3066     ASSERT(pageRects.size() >= 1);
3067     std::size_t pageCount = pageRects.size();
3068     ASSERT(pageCount <= std::numeric_limits<uint32_t>::max());
3069     reply(pageCount);
3070
3071     RetainPtr<CFMutableDataRef> pdfPageData;
3072     drawPagesToPDFImpl(frameID, printInfo, 0, pageCount, pdfPageData);
3073     send(Messages::WebPageProxy::DrawToPDFCallback(IPC::DataReference(CFDataGetBytePtr(pdfPageData.get()), CFDataGetLength(pdfPageData.get())), callbackID));
3074
3075     endPrinting();
3076 }
3077
3078 void WebPage::contentSizeCategoryDidChange(const String& contentSizeCategory)
3079 {
3080     RenderThemeIOS::setContentSizeCategory(contentSizeCategory);
3081     Page::updateStyleForAllPagesAfterGlobalChangeInEnvironment();
3082 }
3083
3084 String WebPage::platformUserAgent(const URL&) const
3085 {
3086     return String();
3087 }
3088
3089 #if USE(QUICK_LOOK)
3090 void WebPage::didReceivePasswordForQuickLookDocument(const String& password)
3091 {
3092     WebPreviewLoaderClient::didReceivePassword(password, m_pageID);
3093 }
3094 #endif
3095
3096 bool WebPage::platformPrefersTextLegibilityBasedZoomScaling() const
3097 {
3098 #if PLATFORM(WATCHOS)
3099     return true;
3100 #else
3101     return false;
3102 #endif
3103 }
3104
3105 #if ENABLE(MEDIA_STREAM)
3106 void WebPage::prepareToSendUserMediaPermissionRequest()
3107 {
3108     static std::once_flag once;
3109     std::call_once(once, [] {
3110         if (!canLoadAVSystemController_PIDToInheritApplicationStateFrom())
3111             return;
3112
3113         NSError *error = nil;
3114         [[getAVSystemControllerClass() sharedAVSystemController] setAttribute:@(WebCore::presentingApplicationPID()) forKey:getAVSystemController_PIDToInheritApplicationStateFrom() error:&error];
3115         if (error)
3116             WTFLogAlways("Failed to set up PID proxying: %s", error.localizedDescription.UTF8String);
3117     });
3118 }
3119 #endif
3120
3121 } // namespace WebKit
3122
3123 #endif // PLATFORM(IOS_FAMILY)