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