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