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