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