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