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