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