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