[iOS][WK2] Pause/resume database thread when UIProcess enters/leaves the background
[WebKit-https.git] / Source / WebKit2 / WebProcess / WebPage / ios / WebPageIOS.mm
1 /*
2  * Copyright (C) 2012-2014 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)
30
31 #import "AssistedNodeInformation.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 "PluginView.h"
39 #import "RemoteLayerTreeDrawingArea.h"
40 #import "UserData.h"
41 #import "VisibleContentRectUpdateInfo.h"
42 #import "WKAccessibilityWebPageObjectIOS.h"
43 #import "WebChromeClient.h"
44 #import "WebCoreArgumentCoders.h"
45 #import "WebDatabaseManager.h"
46 #import "WebFrame.h"
47 #import "WebImage.h"
48 #import "WebKitSystemInterface.h"
49 #import "WebKitSystemInterfaceIOS.h"
50 #import "WebPageProxyMessages.h"
51 #import "WebProcess.h"
52 #import <CoreText/CTFont.h>
53 #import <WebCore/Chrome.h>
54 #import <WebCore/DNS.h>
55 #import <WebCore/DiagnosticLoggingClient.h>
56 #import <WebCore/DiagnosticLoggingKeys.h>
57 #import <WebCore/Element.h>
58 #import <WebCore/ElementAncestorIterator.h>
59 #import <WebCore/EventHandler.h>
60 #import <WebCore/FloatQuad.h>
61 #import <WebCore/FocusController.h>
62 #import <WebCore/Frame.h>
63 #import <WebCore/FrameView.h>
64 #import <WebCore/HTMLElementTypeHelpers.h>
65 #import <WebCore/HTMLFormElement.h>
66 #import <WebCore/HTMLInputElement.h>
67 #import <WebCore/HTMLOptGroupElement.h>
68 #import <WebCore/HTMLOptionElement.h>
69 #import <WebCore/HTMLOptionElement.h>
70 #import <WebCore/HTMLParserIdioms.h>
71 #import <WebCore/HTMLSelectElement.h>
72 #import <WebCore/HTMLTextAreaElement.h>
73 #import <WebCore/HistoryItem.h>
74 #import <WebCore/HitTestResult.h>
75 #import <WebCore/KeyboardEvent.h>
76 #import <WebCore/MainFrame.h>
77 #import <WebCore/MediaSessionManagerIOS.h>
78 #import <WebCore/MemoryPressureHandler.h>
79 #import <WebCore/Node.h>
80 #import <WebCore/NotImplemented.h>
81 #import <WebCore/Page.h>
82 #import <WebCore/Pasteboard.h>
83 #import <WebCore/PlatformKeyboardEvent.h>
84 #import <WebCore/PlatformMouseEvent.h>
85 #import <WebCore/RenderBlock.h>
86 #import <WebCore/RenderImage.h>
87 #import <WebCore/RenderThemeIOS.h>
88 #import <WebCore/RenderView.h>
89 #import <WebCore/SharedBuffer.h>
90 #import <WebCore/StyleProperties.h>
91 #import <WebCore/TextIterator.h>
92 #import <WebCore/VisibleUnits.h>
93 #import <WebCore/WKContentObservation.h>
94 #import <WebCore/WebEvent.h>
95 #import <wtf/MathExtras.h>
96 #import <wtf/TemporaryChange.h>
97
98 using namespace WebCore;
99
100 namespace WebKit {
101
102 const int blockSelectionStartWidth = 100;
103 const int blockSelectionStartHeight = 100;
104
105 void WebPage::platformInitialize()
106 {
107     platformInitializeAccessibility();
108 }
109
110 void WebPage::platformDetach()
111 {
112     [m_mockAccessibilityElement setWebPage:nullptr];
113 }
114     
115 void WebPage::platformInitializeAccessibility()
116 {
117     m_mockAccessibilityElement = adoptNS([[WKAccessibilityWebPageObject alloc] init]);
118     [m_mockAccessibilityElement setWebPage:this];
119     
120     RetainPtr<CFUUIDRef> uuid = adoptCF(CFUUIDCreate(kCFAllocatorDefault));
121     NSData *remoteToken = WKAXRemoteToken(uuid.get());
122     
123     IPC::DataReference dataToken = IPC::DataReference(reinterpret_cast<const uint8_t*>([remoteToken bytes]), [remoteToken length]);
124     send(Messages::WebPageProxy::RegisterWebProcessAccessibilityToken(dataToken));
125 }
126     
127 void WebPage::platformPreferencesDidChange(const WebPreferencesStore&)
128 {
129     notImplemented();
130 }
131
132 void WebPage::platformEditorState(Frame& frame, EditorState& result, IncludePostLayoutDataHint shouldIncludePostLayoutData) const
133 {
134     if (frame.editor().hasComposition()) {
135         RefPtr<Range> compositionRange = frame.editor().compositionRange();
136         Vector<WebCore::SelectionRect> compositionRects;
137         if (compositionRange) {
138             compositionRange->collectSelectionRects(compositionRects);
139             if (compositionRects.size())
140                 result.firstMarkedRect = compositionRects[0].rect();
141             if (compositionRects.size() > 1)
142                 result.lastMarkedRect = compositionRects.last().rect();
143             else
144                 result.lastMarkedRect = result.firstMarkedRect;
145             result.markedText = plainTextReplacingNoBreakSpace(compositionRange.get());
146         }
147     }
148
149     // We only set the remaining EditorState entries if the layout is done. To compute these
150     // entries, we need the layout to be done and we don't want to trigger a synchronous
151     // layout as this would be bad for performance. If we have a composition, we send everything
152     // right away as the UIProcess needs the caretRects ASAP for marked text.
153     if (shouldIncludePostLayoutData == IncludePostLayoutDataHint::No && !frame.editor().hasComposition()) {
154         result.isMissingPostLayoutData = true;
155         return;
156     }
157
158     auto& postLayoutData = result.postLayoutData();
159     FrameView* view = frame.view();
160     const VisibleSelection& selection = frame.selection().selection();
161     if (selection.isCaret()) {
162         postLayoutData.caretRectAtStart = view->contentsToRootView(frame.selection().absoluteCaretBounds());
163         postLayoutData.caretRectAtEnd = postLayoutData.caretRectAtStart;
164         // FIXME: The following check should take into account writing direction.
165         postLayoutData.isReplaceAllowed = result.isContentEditable && atBoundaryOfGranularity(selection.start(), WordGranularity, DirectionForward);
166         postLayoutData.wordAtSelection = plainTextReplacingNoBreakSpace(wordRangeFromPosition(selection.start()).get());
167         if (selection.isContentEditable()) {
168             charactersAroundPosition(selection.start(), postLayoutData.characterAfterSelection, postLayoutData.characterBeforeSelection, postLayoutData.twoCharacterBeforeSelection);
169             Node* root = selection.rootEditableElement();
170             postLayoutData.hasContent = root && root->hasChildNodes() && !isEndOfEditableOrNonEditableContent(firstPositionInNode(root));
171         }
172     } else if (selection.isRange()) {
173         postLayoutData.caretRectAtStart = view->contentsToRootView(VisiblePosition(selection.start()).absoluteCaretBounds());
174         postLayoutData.caretRectAtEnd = view->contentsToRootView(VisiblePosition(selection.end()).absoluteCaretBounds());
175         RefPtr<Range> selectedRange = selection.toNormalizedRange();
176         String selectedText;
177         if (selectedRange) {
178             selectedRange->collectSelectionRects(postLayoutData.selectionRects);
179             convertSelectionRectsToRootView(view, postLayoutData.selectionRects);
180             selectedText = plainTextReplacingNoBreakSpace(selectedRange.get(), TextIteratorDefaultBehavior, true);
181             postLayoutData.selectedTextLength = selectedText.length();
182             const int maxSelectedTextLength = 200;
183             if (selectedText.length() <= maxSelectedTextLength)
184                 postLayoutData.wordAtSelection = selectedText;
185         }
186         // FIXME: We should disallow replace when the string contains only CJ characters.
187         postLayoutData.isReplaceAllowed = result.isContentEditable && !result.isInPasswordField && !selectedText.containsOnlyWhitespace();
188     }
189     if (!selection.isNone()) {
190         if (m_assistedNode && m_assistedNode->renderer())
191             postLayoutData.selectionClipRect = view->contentsToRootView(m_assistedNode->renderer()->absoluteBoundingBoxRect());
192         
193         Node* nodeToRemove;
194         if (RenderStyle* style = Editor::styleForSelectionStart(&frame, nodeToRemove)) {
195             CTFontRef font = style->fontCascade().primaryFont().getCTFont();
196             CTFontSymbolicTraits traits = font ? CTFontGetSymbolicTraits(font) : 0;
197             
198             if (traits & kCTFontTraitBold)
199                 postLayoutData.typingAttributes |= AttributeBold;
200             if (traits & kCTFontTraitItalic)
201                 postLayoutData.typingAttributes |= AttributeItalics;
202             
203             RefPtr<EditingStyle> typingStyle = frame.selection().typingStyle();
204             if (typingStyle && typingStyle->style()) {
205                 String value = typingStyle->style()->getPropertyValue(CSSPropertyWebkitTextDecorationsInEffect);
206                 if (value.contains("underline"))
207                     postLayoutData.typingAttributes |= AttributeUnderline;
208             } else {
209                 if (style->textDecorationsInEffect() & TextDecorationUnderline)
210                     postLayoutData.typingAttributes |= AttributeUnderline;
211             }
212             
213             if (nodeToRemove)
214                 nodeToRemove->remove(ASSERT_NO_EXCEPTION);
215         }
216     }
217 }
218
219 FloatSize WebPage::screenSize() const
220 {
221     return m_screenSize;
222 }
223
224 FloatSize WebPage::availableScreenSize() const
225 {
226     return m_availableScreenSize;
227 }
228
229 void WebPage::viewportPropertiesDidChange(const ViewportArguments& viewportArguments)
230 {
231     if (m_viewportConfiguration.viewportArguments() == viewportArguments)
232         return;
233
234     float oldWidth = m_viewportConfiguration.viewportArguments().width;
235
236     m_viewportConfiguration.setViewportArguments(viewportArguments);
237     viewportConfigurationChanged();
238
239     if (oldWidth != viewportArguments.width)
240         send(Messages::WebPageProxy::ViewportMetaTagWidthDidChange(viewportArguments.width));
241 }
242
243 void WebPage::didReceiveMobileDocType(bool isMobileDoctype)
244 {
245     if (isMobileDoctype)
246         m_viewportConfiguration.setDefaultConfiguration(ViewportConfiguration::xhtmlMobileParameters());
247     else
248         resetViewportDefaultConfiguration(m_mainFrame.get());
249 }
250
251 void WebPage::savePageState(HistoryItem& historyItem)
252 {
253     historyItem.setScaleIsInitial(!m_userHasChangedPageScaleFactor);
254     historyItem.setMinimumLayoutSizeInScrollViewCoordinates(m_viewportConfiguration.minimumLayoutSize());
255     historyItem.setContentSize(m_viewportConfiguration.contentsSize());
256 }
257
258 static double scaleAfterViewportWidthChange(double currentScale, bool userHasChangedPageScaleFactor, const ViewportConfiguration& viewportConfiguration, float unobscuredWidthInScrollViewCoordinates, const IntSize& newContentSize, const IntSize& oldContentSize, float visibleHorizontalFraction)
259 {
260     double scale;
261     if (!userHasChangedPageScaleFactor)
262         scale = viewportConfiguration.initialScale();
263     else
264         scale = std::max(std::min(currentScale, viewportConfiguration.maximumScale()), viewportConfiguration.minimumScale());
265
266     if (userHasChangedPageScaleFactor) {
267         // When the content size changes, we keep the same relative horizontal content width in view, otherwise we would
268         // end up zoomed too far in landscape->portrait, and too close in portrait->landscape.
269         double widthToKeepInView = visibleHorizontalFraction * newContentSize.width();
270         double newScale = unobscuredWidthInScrollViewCoordinates / widthToKeepInView;
271         scale = std::max(std::min(newScale, viewportConfiguration.maximumScale()), viewportConfiguration.minimumScale());
272     }
273     return scale;
274 }
275
276 static FloatPoint relativeCenterAfterContentSizeChange(const FloatRect& originalContentRect, IntSize oldContentSize, IntSize newContentSize)
277 {
278     // If the content size has changed, keep the same relative position.
279     FloatPoint oldContentCenter = originalContentRect.center();
280     float relativeHorizontalPosition = oldContentCenter.x() / oldContentSize.width();
281     float relativeVerticalPosition =  oldContentCenter.y() / oldContentSize.height();
282     return FloatPoint(relativeHorizontalPosition * newContentSize.width(), relativeVerticalPosition * newContentSize.height());
283 }
284
285 static inline FloatRect adjustExposedRectForNewScale(const FloatRect& exposedRect, double exposedRectScale, double newScale)
286 {
287     double overscaledWidth = exposedRect.width();
288     double missingHorizonalMargin = exposedRect.width() * exposedRectScale / newScale - overscaledWidth;
289
290     double overscaledHeight = exposedRect.height();
291     double missingVerticalMargin = exposedRect.height() * exposedRectScale / newScale - overscaledHeight;
292
293     return FloatRect(exposedRect.x() - missingHorizonalMargin / 2, exposedRect.y() - missingVerticalMargin / 2, exposedRect.width() + missingHorizonalMargin, exposedRect.height() + missingVerticalMargin);
294 }
295
296 void WebPage::restorePageState(const HistoryItem& historyItem)
297 {
298     // When a HistoryItem is cleared, its scale factor and scroll point are set to zero. We should not try to restore the other
299     // parameters in those conditions.
300     if (!historyItem.pageScaleFactor())
301         return;
302
303     // We can restore the exposed rect and scale, but we cannot touch the scroll position since the obscured insets
304     // may be changing in the UIProcess. The UIProcess can update the position from the information we send and will then
305     // scroll to the correct position through a regular VisibleContentRectUpdate.
306
307     m_userHasChangedPageScaleFactor = !historyItem.scaleIsInitial();
308
309     FloatSize currentMinimumLayoutSizeInScrollViewCoordinates = m_viewportConfiguration.minimumLayoutSize();
310     if (historyItem.minimumLayoutSizeInScrollViewCoordinates() == currentMinimumLayoutSizeInScrollViewCoordinates) {
311         float boundedScale = std::min<float>(m_viewportConfiguration.maximumScale(), std::max<float>(m_viewportConfiguration.minimumScale(), historyItem.pageScaleFactor()));
312         scalePage(boundedScale, IntPoint());
313
314         m_drawingArea->setExposedContentRect(historyItem.exposedContentRect());
315
316         send(Messages::WebPageProxy::RestorePageState(historyItem.exposedContentRect(), boundedScale));
317     } else {
318         IntSize oldContentSize = historyItem.contentSize();
319         FrameView& frameView = *m_page->mainFrame().view();
320         IntSize newContentSize = frameView.contentsSize();
321         double visibleHorizontalFraction = static_cast<float>(historyItem.unobscuredContentRect().width()) / oldContentSize.width();
322
323         double newScale = scaleAfterViewportWidthChange(historyItem.pageScaleFactor(), !historyItem.scaleIsInitial(), m_viewportConfiguration, currentMinimumLayoutSizeInScrollViewCoordinates.width(), newContentSize, oldContentSize, visibleHorizontalFraction);
324
325         FloatPoint newCenter;
326         if (!oldContentSize.isEmpty() && !newContentSize.isEmpty() && newContentSize != oldContentSize)
327             newCenter = relativeCenterAfterContentSizeChange(historyItem.unobscuredContentRect(), oldContentSize, newContentSize);
328         else
329             newCenter = FloatRect(historyItem.unobscuredContentRect()).center();
330
331         FloatSize unobscuredRectAtNewScale = frameView.customSizeForResizeEvent();
332         unobscuredRectAtNewScale.scale(1 / newScale, 1 / newScale);
333
334         FloatRect oldExposedRect = frameView.exposedContentRect();
335         FloatRect adjustedExposedRect = adjustExposedRectForNewScale(oldExposedRect, m_page->pageScaleFactor(), newScale);
336
337         FloatPoint oldCenter = adjustedExposedRect.center();
338         adjustedExposedRect.move(newCenter - oldCenter);
339
340         scalePage(newScale, IntPoint());
341
342         send(Messages::WebPageProxy::RestorePageCenterAndScale(newCenter, newScale));
343     }
344 }
345
346 double WebPage::minimumPageScaleFactor() const
347 {
348     if (!m_viewportConfiguration.allowsUserScaling())
349         return m_page->pageScaleFactor();
350     return m_viewportConfiguration.minimumScale();
351 }
352
353 double WebPage::maximumPageScaleFactor() const
354 {
355     if (!m_viewportConfiguration.allowsUserScaling())
356         return m_page->pageScaleFactor();
357     return m_viewportConfiguration.maximumScale();
358 }
359
360 bool WebPage::allowsUserScaling() const
361 {
362     return m_viewportConfiguration.allowsUserScaling();
363 }
364
365 bool WebPage::handleEditingKeyboardEvent(KeyboardEvent* event)
366 {
367     const PlatformKeyboardEvent* platformEvent = event->keyEvent();
368     if (!platformEvent)
369         return false;
370
371     // FIXME: Interpret the event immediately upon receiving it in UI process, without sending to WebProcess first.
372     bool eventWasHandled = false;
373     bool sendResult = WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPageProxy::InterpretKeyEvent(editorState(), platformEvent->type() == PlatformKeyboardEvent::Char),
374                                                                                Messages::WebPageProxy::InterpretKeyEvent::Reply(eventWasHandled), m_pageID);
375     if (!sendResult)
376         return false;
377
378     return eventWasHandled;
379 }
380
381 void WebPage::sendComplexTextInputToPlugin(uint64_t, const String&)
382 {
383     notImplemented();
384 }
385
386 void WebPage::performDictionaryLookupAtLocation(const FloatPoint&)
387 {
388     notImplemented();
389 }
390
391 void WebPage::performDictionaryLookupForSelection(Frame*, const VisibleSelection&, TextIndicatorPresentationTransition)
392 {
393     notImplemented();
394 }
395
396 void WebPage::performDictionaryLookupForRange(Frame*, Range&, NSDictionary *, TextIndicatorPresentationTransition)
397 {
398     notImplemented();
399 }
400
401 bool WebPage::performNonEditingBehaviorForSelector(const String&, WebCore::KeyboardEvent*)
402 {
403     notImplemented();
404     return false;
405 }
406
407 bool WebPage::performDefaultBehaviorForKeyEvent(const WebKeyboardEvent&)
408 {
409     notImplemented();
410     return false;
411 }
412
413 void WebPage::getLookupContextAtPoint(const WebCore::IntPoint point, uint64_t callbackID)
414 {
415     Frame& frame = m_page->focusController().focusedOrMainFrame();
416     VisiblePosition position = frame.visiblePositionForPoint(point);
417     String resultString;
418     if (!position.isNull()) {
419         // As context, we are going to use 250 characters of text before and after the point.
420         RefPtr<Range> fullCharacterRange = rangeExpandedAroundPositionByCharacters(position, 250);
421         if (fullCharacterRange)
422             resultString = plainText(fullCharacterRange.get());
423     }
424     send(Messages::WebPageProxy::StringCallback(resultString, callbackID));
425 }
426
427 NSObject *WebPage::accessibilityObjectForMainFramePlugin()
428 {
429     if (!m_page)
430         return 0;
431     
432     if (PluginView* pluginView = pluginViewForFrame(&m_page->mainFrame()))
433         return pluginView->accessibilityObject();
434     
435     return 0;
436 }
437     
438 void WebPage::registerUIProcessAccessibilityTokens(const IPC::DataReference& elementToken, const IPC::DataReference&)
439 {
440     NSData *elementTokenData = [NSData dataWithBytes:elementToken.data() length:elementToken.size()];
441     [m_mockAccessibilityElement setRemoteTokenData:elementTokenData];
442 }
443
444 void WebPage::readSelectionFromPasteboard(const String&, bool&)
445 {
446     notImplemented();
447 }
448
449 void WebPage::getStringSelectionForPasteboard(String&)
450 {
451     notImplemented();
452 }
453
454 void WebPage::getDataSelectionForPasteboard(const String, SharedMemory::Handle&, uint64_t&)
455 {
456     notImplemented();
457 }
458
459 WKAccessibilityWebPageObject* WebPage::accessibilityRemoteObject()
460 {
461     notImplemented();
462     return 0;
463 }
464
465 bool WebPage::platformHasLocalDataForURL(const WebCore::URL&)
466 {
467     notImplemented();
468     return false;
469 }
470
471 String WebPage::cachedSuggestedFilenameForURL(const URL&)
472 {
473     notImplemented();
474     return String();
475 }
476
477 String WebPage::cachedResponseMIMETypeForURL(const URL&)
478 {
479     notImplemented();
480     return String();
481 }
482
483 PassRefPtr<SharedBuffer> WebPage::cachedResponseDataForURL(const URL&)
484 {
485     notImplemented();
486     return 0;
487 }
488
489 bool WebPage::platformCanHandleRequest(const WebCore::ResourceRequest&)
490 {
491     notImplemented();
492     return false;
493 }
494
495 void WebPage::shouldDelayWindowOrderingEvent(const WebKit::WebMouseEvent&, bool&)
496 {
497     notImplemented();
498 }
499
500 void WebPage::acceptsFirstMouse(int, const WebKit::WebMouseEvent&, bool&)
501 {
502     notImplemented();
503 }
504
505 void WebPage::computePagesForPrintingPDFDocument(uint64_t, const PrintInfo&, Vector<IntRect>&)
506 {
507     notImplemented();
508 }
509
510 void WebPage::drawPagesToPDFFromPDFDocument(CGContextRef, PDFDocument *, const PrintInfo&, uint32_t, uint32_t)
511 {
512     notImplemented();
513 }
514
515 void WebPage::advanceToNextMisspelling(bool)
516 {
517     notImplemented();
518 }
519
520 IntRect WebPage::rectForElementAtInteractionLocation()
521 {
522     HitTestResult result = m_page->mainFrame().eventHandler().hitTestResultAtPoint(m_lastInteractionLocation, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::AllowChildFrameContent);
523     Node* hitNode = result.innerNode();
524     if (!hitNode || !hitNode->renderer())
525         return IntRect();
526     return result.innerNodeFrame()->view()->contentsToRootView(hitNode->renderer()->absoluteBoundingBoxRect(true));
527 }
528
529 void WebPage::updateSelectionAppearance()
530 {
531     Frame& frame = m_page->focusController().focusedOrMainFrame();
532     if (!frame.editor().ignoreCompositionSelectionChange() && (frame.editor().hasComposition() || !frame.selection().selection().isNone()))
533         didChangeSelection();
534 }
535
536 void WebPage::handleSyntheticClick(Node* nodeRespondingToClick, const WebCore::FloatPoint& location)
537 {
538     IntPoint roundedAdjustedPoint = roundedIntPoint(location);
539     Frame& mainframe = m_page->mainFrame();
540
541     WKBeginObservingContentChanges(true);
542
543     mainframe.eventHandler().mouseMoved(PlatformMouseEvent(roundedAdjustedPoint, roundedAdjustedPoint, NoButton, PlatformEvent::MouseMoved, 0, false, false, false, false, 0, WebCore::ForceAtClick));
544     mainframe.document()->updateStyleIfNeeded();
545
546     WKStopObservingContentChanges();
547
548     m_pendingSyntheticClickNode = nullptr;
549     m_pendingSyntheticClickLocation = FloatPoint();
550
551     switch (WKObservedContentChange()) {
552     case WKContentVisibilityChange:
553         // The move event caused new contents to appear. Don't send the click event.
554         return;
555     case WKContentIndeterminateChange:
556         // Wait for callback to completePendingSyntheticClickForContentChangeObserver() to decide whether to send the click event.
557         m_pendingSyntheticClickNode = nodeRespondingToClick;
558         m_pendingSyntheticClickLocation = location;
559         return;
560     case WKContentNoChange:
561         completeSyntheticClick(nodeRespondingToClick, location);
562         return;
563     }
564     ASSERT_NOT_REACHED();
565 }
566
567 void WebPage::completePendingSyntheticClickForContentChangeObserver()
568 {
569     if (!m_pendingSyntheticClickNode)
570         return;
571     // Only dispatch the click if the document didn't get changed by any timers started by the move event.
572     if (WKObservedContentChange() == WKContentNoChange)
573         completeSyntheticClick(m_pendingSyntheticClickNode.get(), m_pendingSyntheticClickLocation);
574
575     m_pendingSyntheticClickNode = nullptr;
576     m_pendingSyntheticClickLocation = FloatPoint();
577 }
578
579 void WebPage::completeSyntheticClick(Node* nodeRespondingToClick, const WebCore::FloatPoint& location)
580 {
581     IntPoint roundedAdjustedPoint = roundedIntPoint(location);
582     Frame& mainframe = m_page->mainFrame();
583
584     RefPtr<Frame> oldFocusedFrame = m_page->focusController().focusedFrame();
585     RefPtr<Element> oldFocusedElement = oldFocusedFrame ? oldFocusedFrame->document()->focusedElement() : nullptr;
586     m_userIsInteracting = true;
587
588     bool tapWasHandled = false;
589     m_lastInteractionLocation = roundedAdjustedPoint;
590     tapWasHandled |= mainframe.eventHandler().handleMousePressEvent(PlatformMouseEvent(roundedAdjustedPoint, roundedAdjustedPoint, LeftButton, PlatformEvent::MousePressed, 1, false, false, false, false, 0, WebCore::ForceAtClick));
591     tapWasHandled |= mainframe.eventHandler().handleMouseReleaseEvent(PlatformMouseEvent(roundedAdjustedPoint, roundedAdjustedPoint, LeftButton, PlatformEvent::MouseReleased, 1, false, false, false, false, 0, WebCore::ForceAtClick));
592
593     RefPtr<Frame> newFocusedFrame = m_page->focusController().focusedFrame();
594     RefPtr<Element> newFocusedElement = newFocusedFrame ? newFocusedFrame->document()->focusedElement() : nullptr;
595
596     // If the focus has not changed, we need to notify the client anyway, since it might be
597     // necessary to start assisting the node.
598     // If the node has been focused by JavaScript without user interaction, the
599     // keyboard is not on screen.
600     if (newFocusedElement && newFocusedElement == oldFocusedElement)
601         elementDidFocus(newFocusedElement.get());
602
603     m_userIsInteracting = false;
604
605     if (!tapWasHandled || !nodeRespondingToClick || !nodeRespondingToClick->isElementNode())
606         send(Messages::WebPageProxy::DidNotHandleTapAsClick(roundedIntPoint(location)));
607 }
608
609 void WebPage::handleTap(const IntPoint& point, uint64_t lastLayerTreeTransactionId)
610 {
611     if (lastLayerTreeTransactionId < m_firstLayerTreeTransactionIDAfterDidCommitLoad) {
612         send(Messages::WebPageProxy::DidNotHandleTapAsClick(roundedIntPoint(m_potentialTapLocation)));
613         return;
614     }
615
616     FloatPoint adjustedPoint;
617     Node* nodeRespondingToClick = m_page->mainFrame().nodeRespondingToClickEvents(point, adjustedPoint);
618     handleSyntheticClick(nodeRespondingToClick, adjustedPoint);
619 }
620
621 void WebPage::sendTapHighlightForNodeIfNecessary(uint64_t requestID, Node* node)
622 {
623 #if ENABLE(TOUCH_EVENTS)
624     if (!node)
625         return;
626
627     if (is<Element>(*node))
628         prefetchDNS(downcast<Element>(*node).absoluteLinkURL().host());
629
630     Vector<FloatQuad> quads;
631     if (RenderObject *renderer = node->renderer()) {
632         renderer->absoluteQuads(quads);
633         Color highlightColor = renderer->style().tapHighlightColor();
634         if (!node->document().frame()->isMainFrame()) {
635             FrameView* view = node->document().frame()->view();
636             for (size_t i = 0; i < quads.size(); ++i) {
637                 FloatQuad& currentQuad = quads[i];
638                 currentQuad.setP1(view->contentsToRootView(roundedIntPoint(currentQuad.p1())));
639                 currentQuad.setP2(view->contentsToRootView(roundedIntPoint(currentQuad.p2())));
640                 currentQuad.setP3(view->contentsToRootView(roundedIntPoint(currentQuad.p3())));
641                 currentQuad.setP4(view->contentsToRootView(roundedIntPoint(currentQuad.p4())));
642             }
643         }
644
645         RoundedRect::Radii borderRadii;
646         if (is<RenderBox>(*renderer))
647             borderRadii = downcast<RenderBox>(*renderer).borderRadii();
648
649         send(Messages::WebPageProxy::DidGetTapHighlightGeometries(requestID, highlightColor, quads, roundedIntSize(borderRadii.topLeft()), roundedIntSize(borderRadii.topRight()), roundedIntSize(borderRadii.bottomLeft()), roundedIntSize(borderRadii.bottomRight())));
650     }
651 #else
652     UNUSED_PARAM(requestID);
653     UNUSED_PARAM(node);
654 #endif
655 }
656
657 void WebPage::potentialTapAtPosition(uint64_t requestID, const WebCore::FloatPoint& position)
658 {
659     m_potentialTapNode = m_page->mainFrame().nodeRespondingToClickEvents(position, m_potentialTapLocation);
660     sendTapHighlightForNodeIfNecessary(requestID, m_potentialTapNode.get());
661 }
662
663 void WebPage::commitPotentialTap(uint64_t lastLayerTreeTransactionId)
664 {
665     if (!m_potentialTapNode || !m_potentialTapNode->renderer() || lastLayerTreeTransactionId < m_firstLayerTreeTransactionIDAfterDidCommitLoad) {
666         commitPotentialTapFailed();
667         return;
668     }
669
670     FloatPoint adjustedPoint;
671     Node* nodeRespondingToClick = m_page->mainFrame().nodeRespondingToClickEvents(m_potentialTapLocation, adjustedPoint);
672
673     if (m_potentialTapNode == nodeRespondingToClick)
674         handleSyntheticClick(nodeRespondingToClick, adjustedPoint);
675     else
676         commitPotentialTapFailed();
677
678     m_potentialTapNode = nullptr;
679     m_potentialTapLocation = FloatPoint();
680 }
681
682 void WebPage::commitPotentialTapFailed()
683 {
684     send(Messages::WebPageProxy::CommitPotentialTapFailed());
685     send(Messages::WebPageProxy::DidNotHandleTapAsClick(roundedIntPoint(m_potentialTapLocation)));
686 }
687
688 void WebPage::cancelPotentialTap()
689 {
690     m_potentialTapNode = nullptr;
691     m_potentialTapLocation = FloatPoint();
692 }
693
694 void WebPage::tapHighlightAtPosition(uint64_t requestID, const FloatPoint& position)
695 {
696     Frame& mainframe = m_page->mainFrame();
697     FloatPoint adjustedPoint;
698     sendTapHighlightForNodeIfNecessary(requestID, mainframe.nodeRespondingToClickEvents(position, adjustedPoint));
699 }
700
701 void WebPage::inspectorNodeSearchMovedToPosition(const FloatPoint& position)
702 {
703     IntPoint adjustedPoint = roundedIntPoint(position);
704     Frame& mainframe = m_page->mainFrame();
705
706     mainframe.eventHandler().mouseMoved(PlatformMouseEvent(adjustedPoint, adjustedPoint, NoButton, PlatformEvent::MouseMoved, 0, false, false, false, false, 0, 0));
707     mainframe.document()->updateStyleIfNeeded();
708 }
709
710 void WebPage::inspectorNodeSearchEndedAtPosition(const FloatPoint& position)
711 {
712     if (Node* node = m_page->mainFrame().deepestNodeAtLocation(position))
713         node->inspect();
714 }
715
716 void WebPage::blurAssistedNode()
717 {
718     if (is<Element>(m_assistedNode.get()))
719         downcast<Element>(*m_assistedNode).blur();
720 }
721
722 void WebPage::setAssistedNodeValue(const String& value)
723 {
724     if (is<HTMLInputElement>(m_assistedNode.get())) {
725         HTMLInputElement& element = downcast<HTMLInputElement>(*m_assistedNode);
726         element.setValue(value, DispatchInputAndChangeEvent);
727     }
728     // FIXME: should also handle the case of HTMLSelectElement.
729 }
730
731 void WebPage::setAssistedNodeValueAsNumber(double value)
732 {
733     if (is<HTMLInputElement>(m_assistedNode.get())) {
734         HTMLInputElement& element = downcast<HTMLInputElement>(*m_assistedNode);
735         element.setValueAsNumber(value, ASSERT_NO_EXCEPTION, DispatchInputAndChangeEvent);
736     }
737 }
738
739 void WebPage::setAssistedNodeSelectedIndex(uint32_t index, bool allowMultipleSelection)
740 {
741     if (!is<HTMLSelectElement>(m_assistedNode.get()))
742         return;
743     HTMLSelectElement& select = downcast<HTMLSelectElement>(*m_assistedNode);
744     select.optionSelectedByUser(index, true, allowMultipleSelection);
745 }
746
747 void WebPage::showInspectorHighlight(const WebCore::Highlight& highlight)
748 {
749     send(Messages::WebPageProxy::ShowInspectorHighlight(highlight));
750 }
751
752 void WebPage::hideInspectorHighlight()
753 {
754     send(Messages::WebPageProxy::HideInspectorHighlight());
755 }
756
757 void WebPage::showInspectorIndication()
758 {
759     send(Messages::WebPageProxy::ShowInspectorIndication());
760 }
761
762 void WebPage::hideInspectorIndication()
763 {
764     send(Messages::WebPageProxy::HideInspectorIndication());
765 }
766
767 void WebPage::enableInspectorNodeSearch()
768 {
769     send(Messages::WebPageProxy::EnableInspectorNodeSearch());
770 }
771
772 void WebPage::disableInspectorNodeSearch()
773 {
774     send(Messages::WebPageProxy::DisableInspectorNodeSearch());
775 }
776
777 static FloatQuad innerFrameQuad(Frame* frame, Node* assistedNode)
778 {
779     frame->document()->updateLayoutIgnorePendingStylesheets();
780     RenderObject* renderer;
781     if (assistedNode->hasTagName(HTMLNames::textareaTag) || assistedNode->hasTagName(HTMLNames::inputTag) || assistedNode->hasTagName(HTMLNames::selectTag))
782         renderer = assistedNode->renderer();
783     else
784         renderer = assistedNode->rootEditableElement()->renderer();
785     
786     if (!renderer)
787         return FloatQuad();
788
789     RenderStyle& style = renderer->style();
790     IntRect boundingBox = renderer->absoluteBoundingBoxRect(true /* use transforms*/);
791
792     boundingBox.move(style.borderLeftWidth(), style.borderTopWidth());
793     boundingBox.setWidth(boundingBox.width() - style.borderLeftWidth() - style.borderRightWidth());
794     boundingBox.setHeight(boundingBox.height() - style.borderBottomWidth() - style.borderTopWidth());
795
796     return FloatQuad(boundingBox);
797 }
798
799 static IntPoint constrainPoint(const IntPoint& point, Frame* frame, Node* assistedNode)
800 {
801     ASSERT(!assistedNode || &assistedNode->document() == frame->document());
802     const int DEFAULT_CONSTRAIN_INSET = 2;
803     IntRect innerFrame = innerFrameQuad(frame, assistedNode).enclosingBoundingBox();
804     IntPoint constrainedPoint = point;
805
806     int minX = innerFrame.x() + DEFAULT_CONSTRAIN_INSET;
807     int maxX = innerFrame.maxX() - DEFAULT_CONSTRAIN_INSET;
808     int minY = innerFrame.y() + DEFAULT_CONSTRAIN_INSET;
809     int maxY = innerFrame.maxY() - DEFAULT_CONSTRAIN_INSET;
810
811     if (point.x() < minX)
812         constrainedPoint.setX(minX);
813     else if (point.x() > maxX)
814         constrainedPoint.setX(maxX);
815
816     if (point.y() < minY)
817         constrainedPoint.setY(minY);
818     else if (point.y() >= maxY)
819         constrainedPoint.setY(maxY);
820                     
821     return constrainedPoint;
822 }
823
824 static IntRect selectionBoxForRange(WebCore::Range* range)
825 {
826     if (!range)
827         return IntRect();
828     
829     IntRect boundingRect;
830     Vector<SelectionRect> selectionRects;
831     range->collectSelectionRects(selectionRects);
832     unsigned size = selectionRects.size();
833     
834     for (unsigned i = 0; i < size; ++i) {
835         const IntRect &coreRect = selectionRects[i].rect();
836         if (!i)
837             boundingRect = coreRect;
838         else
839             boundingRect.unite(coreRect);
840     }
841     return boundingRect;
842 }
843
844 PassRefPtr<Range> WebPage::rangeForWebSelectionAtPosition(const IntPoint& point, const VisiblePosition& position, SelectionFlags& flags)
845 {
846     HitTestResult result = m_page->mainFrame().eventHandler().hitTestResultAtPoint((point), HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShadowContent | HitTestRequest::AllowChildFrameContent);
847
848     Node* currentNode = result.innerNode();
849     RefPtr<Range> range;
850     FloatRect boundingRectInScrollViewCoordinates;
851
852     if (currentNode->isTextNode()) {
853         range = enclosingTextUnitOfGranularity(position, ParagraphGranularity, DirectionForward);
854         if (!range || range->collapsed(ASSERT_NO_EXCEPTION))
855             range = Range::create(currentNode->document(), position, position);
856         if (!range)
857             return nullptr;
858
859         boundingRectInScrollViewCoordinates = selectionBoxForRange(range.get());
860         boundingRectInScrollViewCoordinates.scale(m_page->pageScaleFactor());
861         if (boundingRectInScrollViewCoordinates.width() > m_blockSelectionDesiredSize.width() && boundingRectInScrollViewCoordinates.height() > m_blockSelectionDesiredSize.height())
862             return wordRangeFromPosition(position);
863
864         currentNode = range->commonAncestorContainer(ASSERT_NO_EXCEPTION);
865     }
866
867     if (!currentNode->isElementNode())
868         currentNode = currentNode->parentElement();
869
870     Node* bestChoice = currentNode;
871     while (currentNode) {
872         if (currentNode->renderer()) {
873             boundingRectInScrollViewCoordinates = currentNode->renderer()->absoluteBoundingBoxRect(true);
874             boundingRectInScrollViewCoordinates.scale(m_page->pageScaleFactor());
875             if (boundingRectInScrollViewCoordinates.width() > m_blockSelectionDesiredSize.width() && boundingRectInScrollViewCoordinates.height() > m_blockSelectionDesiredSize.height())
876                 break;
877             bestChoice = currentNode;
878         }
879         currentNode = currentNode->parentElement();
880     }
881
882     if (!bestChoice)
883         return nullptr;
884
885     RenderObject* renderer = bestChoice->renderer();
886     if (!renderer || renderer->style().userSelect() == SELECT_NONE)
887         return nullptr;
888
889     if (renderer->childrenInline() && (is<RenderBlock>(*renderer) && !downcast<RenderBlock>(*renderer).inlineElementContinuation()) && !renderer->isTable()) {
890         range = enclosingTextUnitOfGranularity(position, WordGranularity, DirectionBackward);
891         if (range && !range->collapsed(ASSERT_NO_EXCEPTION))
892             return range;
893     }
894
895     // If all we could find is a block whose height is very close to the height
896     // of the visible area, don't use it.
897     const float adjustmentFactor = .97;
898     boundingRectInScrollViewCoordinates = renderer->absoluteBoundingBoxRect(true);
899
900     if (boundingRectInScrollViewCoordinates.height() > m_page->mainFrame().view()->exposedContentRect().height() * adjustmentFactor)
901         return nullptr;
902
903     flags = IsBlockSelection;
904     range = Range::create(bestChoice->document());
905     range->selectNodeContents(bestChoice, ASSERT_NO_EXCEPTION);
906     return range->collapsed(ASSERT_NO_EXCEPTION) ? nullptr : range;
907 }
908
909 PassRefPtr<Range> WebPage::rangeForBlockAtPoint(const IntPoint& point)
910 {
911     HitTestResult result = m_page->mainFrame().eventHandler().hitTestResultAtPoint((point), HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShadowContent | HitTestRequest::IgnoreClipping);
912
913     Node* currentNode = result.innerNode();
914     RefPtr<Range> range;
915
916     if (currentNode->isTextNode()) {
917         range = enclosingTextUnitOfGranularity(m_page->focusController().focusedOrMainFrame().visiblePositionForPoint(point), ParagraphGranularity, DirectionForward);
918         if (range && !range->collapsed(ASSERT_NO_EXCEPTION))
919             return range;
920     }
921
922     if (!currentNode->isElementNode())
923         currentNode = currentNode->parentElement();
924
925     if (!currentNode)
926         return nullptr;
927
928     range = Range::create(currentNode->document());
929     range->selectNodeContents(currentNode, ASSERT_NO_EXCEPTION);
930     return range;
931 }
932
933 void WebPage::selectWithGesture(const IntPoint& point, uint32_t granularity, uint32_t gestureType, uint32_t gestureState, uint64_t callbackID)
934 {
935     Frame& frame = m_page->focusController().focusedOrMainFrame();
936     VisiblePosition position = visiblePositionInFocusedNodeForPoint(frame, point);
937
938     if (position.isNull()) {
939         send(Messages::WebPageProxy::GestureCallback(point, gestureType, gestureState, 0, callbackID));
940         return;
941     }
942     RefPtr<Range> range;
943     SelectionFlags flags = None;
944     GestureRecognizerState wkGestureState = static_cast<GestureRecognizerState>(gestureState);
945     switch (static_cast<GestureType>(gestureType)) {
946     case GestureType::PhraseBoundary:
947     {
948         if (!frame.editor().hasComposition())
949             break;
950         RefPtr<Range> markedRange = frame.editor().compositionRange();
951         if (position < markedRange->startPosition())
952             position = markedRange->startPosition();
953         if (position > markedRange->endPosition())
954             position = markedRange->endPosition();
955         if (wkGestureState != GestureRecognizerState::Began)
956             flags = distanceBetweenPositions(markedRange->startPosition(), frame.selection().selection().start()) != distanceBetweenPositions(markedRange->startPosition(), position) ? PhraseBoundaryChanged : None;
957         else
958             flags = PhraseBoundaryChanged;
959         range = Range::create(*frame.document(), position, position);
960     }
961         break;
962
963     case GestureType::OneFingerTap:
964     {
965         VisiblePosition result;
966         // move the the position at the end of the word
967         if (atBoundaryOfGranularity(position, LineGranularity, DirectionForward)) {
968             // Don't cross line boundaries.
969             result = position;
970         } else if (withinTextUnitOfGranularity(position, WordGranularity, DirectionForward)) {
971             // The position lies within a word.
972             RefPtr<Range> wordRange = enclosingTextUnitOfGranularity(position, WordGranularity, DirectionForward);
973             if (wordRange) {
974                 result = wordRange->startPosition();
975                 if (distanceBetweenPositions(position, result) > 1)
976                     result = wordRange->endPosition();
977             }
978         } else if (atBoundaryOfGranularity(position, WordGranularity, DirectionBackward)) {
979             // The position is at the end of a word.
980             result = position;
981         } else {
982             // The position is not within a word.
983             // Go to the next boundary.
984             result = positionOfNextBoundaryOfGranularity(position, WordGranularity, DirectionForward);
985
986             // If there is no such boundary we go to the end of the element.
987             if (result.isNull())
988                 result = endOfEditableContent(position);
989         }
990         if (result.isNotNull())
991             range = Range::create(*frame.document(), result, result);
992     }
993         break;
994
995     case GestureType::Loupe:
996         if (position.rootEditableElement())
997             range = Range::create(*frame.document(), position, position);
998         else
999             range = wordRangeFromPosition(position);
1000         break;
1001
1002     case GestureType::TapAndAHalf:
1003         switch (wkGestureState) {
1004         case GestureRecognizerState::Began:
1005             range = wordRangeFromPosition(position);
1006             m_currentWordRange = range ? RefPtr<Range>(Range::create(*frame.document(), range->startPosition(), range->endPosition())) : nullptr;
1007             break;
1008         case GestureRecognizerState::Changed:
1009             if (!m_currentWordRange)
1010                 break;
1011             range = Range::create(*frame.document(), m_currentWordRange->startPosition(), m_currentWordRange->endPosition());
1012             if (position < range->startPosition())
1013                 range->setStart(position.deepEquivalent(), ASSERT_NO_EXCEPTION);
1014             if (position > range->endPosition())
1015                 range->setEnd(position.deepEquivalent(), ASSERT_NO_EXCEPTION);
1016             break;
1017         case GestureRecognizerState::Ended:
1018         case GestureRecognizerState::Cancelled:
1019             m_currentWordRange = nullptr;
1020             break;
1021         case GestureRecognizerState::Failed:
1022         case GestureRecognizerState::Possible:
1023             ASSERT_NOT_REACHED();
1024         }
1025         break;
1026
1027     case GestureType::OneFingerDoubleTap:
1028         if (atBoundaryOfGranularity(position, LineGranularity, DirectionForward)) {
1029             // Double-tap at end of line only places insertion point there.
1030             // This helps to get the callout for pasting at ends of lines,
1031             // paragraphs, and documents.
1032             range = Range::create(*frame.document(), position, position);
1033          } else
1034             range = wordRangeFromPosition(position);
1035         break;
1036
1037     case GestureType::TwoFingerSingleTap:
1038         // Single tap with two fingers selects the entire paragraph.
1039         range = enclosingTextUnitOfGranularity(position, ParagraphGranularity, DirectionForward);
1040         break;
1041
1042     case GestureType::OneFingerTripleTap:
1043         if (atBoundaryOfGranularity(position, LineGranularity, DirectionForward)) {
1044             // Triple-tap at end of line only places insertion point there.
1045             // This helps to get the callout for pasting at ends of lines,
1046             // paragraphs, and documents.
1047             range = Range::create(*frame.document(), position, position);
1048         } else
1049             range = enclosingTextUnitOfGranularity(position, ParagraphGranularity, DirectionForward);
1050         break;
1051
1052     case GestureType::MakeWebSelection:
1053         if (wkGestureState == GestureRecognizerState::Began) {
1054             m_blockSelectionDesiredSize.setWidth(blockSelectionStartWidth);
1055             m_blockSelectionDesiredSize.setHeight(blockSelectionStartHeight);
1056             m_currentBlockSelection = nullptr;
1057         }
1058         range = rangeForWebSelectionAtPosition(point, position, flags);
1059         if (wkGestureState == GestureRecognizerState::Ended && flags & IsBlockSelection)
1060             m_currentBlockSelection = range;
1061         break;
1062
1063     default:
1064         break;
1065     }
1066     if (range)
1067         frame.selection().setSelectedRange(range.get(), position.affinity(), true);
1068
1069     send(Messages::WebPageProxy::GestureCallback(point, gestureType, gestureState, static_cast<uint32_t>(flags), callbackID));
1070 }
1071
1072 static PassRefPtr<Range> rangeForPosition(Frame* frame, const VisiblePosition& position, bool baseIsStart)
1073 {
1074     RefPtr<Range> range;
1075     VisiblePosition result = position;
1076
1077     if (baseIsStart) {
1078         VisiblePosition selectionStart = frame->selection().selection().visibleStart();
1079         bool wouldFlip = position <= selectionStart;
1080
1081         if (wouldFlip)
1082             result = selectionStart.next();
1083
1084         if (result.isNotNull())
1085             range = Range::create(*frame->document(), selectionStart, result);
1086     } else {
1087         VisiblePosition selectionEnd = frame->selection().selection().visibleEnd();
1088         bool wouldFlip = position >= selectionEnd;
1089
1090         if (wouldFlip)
1091             result = selectionEnd.previous();
1092
1093         if (result.isNotNull())
1094             range = Range::create(*frame->document(), result, selectionEnd);
1095     }
1096
1097     return range.release();
1098 }
1099
1100 static PassRefPtr<Range> rangeAtWordBoundaryForPosition(Frame* frame, const VisiblePosition& position, bool baseIsStart, SelectionDirection direction)
1101 {
1102     SelectionDirection sameDirection = baseIsStart ? DirectionForward : DirectionBackward;
1103     SelectionDirection oppositeDirection = baseIsStart ? DirectionBackward : DirectionForward;
1104     VisiblePosition base = baseIsStart ? frame->selection().selection().visibleStart() : frame->selection().selection().visibleEnd();
1105     VisiblePosition extent = baseIsStart ? frame->selection().selection().visibleEnd() : frame->selection().selection().visibleStart();
1106     VisiblePosition initialExtent = position;
1107
1108     if (atBoundaryOfGranularity(extent, WordGranularity, sameDirection)) {
1109         // This is a word boundary. Leave selection where it is.
1110         return 0;
1111     }
1112
1113     if (atBoundaryOfGranularity(extent, WordGranularity, oppositeDirection)) {
1114         // This is a word boundary in the wrong direction. Nudge the selection to a character before proceeding.
1115         extent = baseIsStart ? extent.previous() : extent.next();
1116     }
1117
1118     // Extend to the boundary of the word.
1119
1120     VisiblePosition wordBoundary = positionOfNextBoundaryOfGranularity(extent, WordGranularity, sameDirection);
1121     if (wordBoundary.isNotNull()
1122         && atBoundaryOfGranularity(wordBoundary, WordGranularity, sameDirection)
1123         && initialExtent != wordBoundary) {
1124         extent = wordBoundary;
1125         return (base < extent) ? Range::create(*frame->document(), base, extent) : Range::create(*frame->document(), extent, base);
1126     }
1127     // Conversely, if the initial extent equals the current word boundary, then
1128     // run the rest of this function to see if the selection should extend
1129     // the other direction to the other word.
1130
1131     // If this is where the extent was initially, then iterate in the other direction in the document until we hit the next word.
1132     while (extent.isNotNull()
1133            && !atBoundaryOfGranularity(extent, WordGranularity, sameDirection)
1134            && extent != base
1135            && !atBoundaryOfGranularity(extent, LineBoundary, sameDirection)
1136            && !atBoundaryOfGranularity(extent, LineBoundary, oppositeDirection)) {
1137         extent = baseIsStart ? extent.next() : extent.previous();
1138     }
1139
1140     // Don't let the smart extension make the extent equal the base.
1141     // Expand out to word boundary.
1142     if (extent.isNull() || extent == base)
1143         extent = wordBoundary;
1144     if (extent.isNull())
1145         return 0;
1146
1147     return (base < extent) ? Range::create(*frame->document(), base, extent) : Range::create(*frame->document(), extent, base);
1148 }
1149
1150 static const int maxHitTests = 10;
1151
1152 static inline float distanceBetweenRectsForPosition(IntRect& first, IntRect& second, SelectionHandlePosition handlePosition)
1153 {
1154     switch (handlePosition) {
1155     case SelectionHandlePosition::Top:
1156         return abs(first.y() - second.y());
1157     case SelectionHandlePosition::Right:
1158         return abs(first.maxX() - second.maxX());
1159     case SelectionHandlePosition::Bottom:
1160         return abs(first.maxY() - second.maxY());
1161     case SelectionHandlePosition::Left:
1162         return abs(first.x() - second.x());
1163     }
1164 }
1165
1166 static inline bool rectsEssentiallyTheSame(IntRect& first, IntRect& second, float allowablePercentDifference)
1167 {
1168     const float minMagnitudeRatio = 1.0 - allowablePercentDifference;
1169     const float maxDisplacementRatio = allowablePercentDifference;
1170
1171     float xOriginShiftRatio = abs(first.x() - second.x())/std::min(first.width(), second.width());
1172     float yOriginShiftRatio = abs(first.y() - second.y())/std::min(first.height(), second.height());
1173
1174     float widthRatio = std::min(first.width() / second.width(), second.width() / first.width());
1175     float heightRatio = std::min(first.height() / second.height(), second.height() / first.height());
1176     return ((widthRatio > minMagnitudeRatio && xOriginShiftRatio < maxDisplacementRatio)
1177         && (heightRatio > minMagnitudeRatio && yOriginShiftRatio < maxDisplacementRatio));
1178 }
1179
1180 static inline bool containsRange(Range* first, Range* second)
1181 {
1182     if (!first || !second)
1183         return false;
1184     return (first->commonAncestorContainer(ASSERT_NO_EXCEPTION)->ownerDocument() == second->commonAncestorContainer(ASSERT_NO_EXCEPTION)->ownerDocument()
1185         && first->compareBoundaryPoints(Range::START_TO_START, second, ASSERT_NO_EXCEPTION) <= 0
1186         && first->compareBoundaryPoints(Range::END_TO_END, second, ASSERT_NO_EXCEPTION) >= 0);
1187 }
1188
1189 static inline RefPtr<Range> unionDOMRanges(Range* rangeA, Range* rangeB)
1190 {
1191     if (!rangeB)
1192         return rangeA;
1193     if (!rangeA)
1194         return rangeB;
1195
1196     Range* start = rangeA->compareBoundaryPoints(Range::START_TO_START, rangeB, ASSERT_NO_EXCEPTION) <= 0 ? rangeA : rangeB;
1197     Range* end = rangeA->compareBoundaryPoints(Range::END_TO_END, rangeB, ASSERT_NO_EXCEPTION) <= 0 ? rangeB : rangeA;
1198
1199     return Range::create(rangeA->ownerDocument(), start->startContainer(), start->startOffset(), end->endContainer(), end->endOffset());
1200 }
1201
1202 static inline IntPoint computeEdgeCenter(const IntRect& box, SelectionHandlePosition handlePosition)
1203 {
1204     switch (handlePosition) {
1205     case SelectionHandlePosition::Top:
1206         return IntPoint(box.x() + box.width() / 2, box.y());
1207     case SelectionHandlePosition::Right:
1208         return IntPoint(box.maxX(), box.y() + box.height() / 2);
1209     case SelectionHandlePosition::Bottom:
1210         return IntPoint(box.x() + box.width() / 2, box.maxY());
1211     case SelectionHandlePosition::Left:
1212         return IntPoint(box.x(), box.y() + box.height() / 2);
1213     }
1214 }
1215
1216 PassRefPtr<Range> WebPage::expandedRangeFromHandle(Range* currentRange, SelectionHandlePosition handlePosition)
1217 {
1218     IntRect currentBox = selectionBoxForRange(currentRange);
1219     IntPoint edgeCenter = computeEdgeCenter(currentBox, handlePosition);
1220     static const float maxDistance = 1000;
1221     const float multiple = powf(maxDistance, 1.0/(maxHitTests - 1));
1222     float distance = 1;
1223
1224     RefPtr<Range> bestRange;
1225     IntRect bestRect;
1226
1227     while (distance < maxDistance) {
1228         if (bestRange) {
1229             if (distanceBetweenRectsForPosition(bestRect, currentBox, handlePosition) < distance) {
1230                 // Break early, we're unlikely to do any better.
1231                 break;
1232             }
1233         }
1234
1235         IntPoint testPoint = edgeCenter;
1236         switch (handlePosition) {
1237         case SelectionHandlePosition::Top:
1238             testPoint.move(0, -distance);
1239             break;
1240         case SelectionHandlePosition::Right:
1241             testPoint.move(distance, 0);
1242             break;
1243         case SelectionHandlePosition::Bottom:
1244             testPoint.move(0, distance);
1245             break;
1246         case SelectionHandlePosition::Left:
1247             testPoint.move(-distance, 0);
1248             break;
1249         }
1250
1251         distance = ceilf(distance * multiple);
1252
1253         RefPtr<Range> newRange;
1254         RefPtr<Range> rangeAtPosition = rangeForBlockAtPoint(testPoint);
1255         if (!rangeAtPosition || &currentRange->ownerDocument() != &rangeAtPosition->ownerDocument())
1256             continue;
1257
1258         if (containsRange(rangeAtPosition.get(), currentRange))
1259             newRange = rangeAtPosition;
1260         else if (containsRange(currentRange, rangeAtPosition.get()))
1261             newRange = currentRange;
1262         else
1263             newRange = unionDOMRanges(currentRange, rangeAtPosition.get());
1264
1265         IntRect copyRect = selectionBoxForRange(newRange.get());
1266
1267         // Is it different and bigger than the current?
1268         bool isBetterChoice = !(rectsEssentiallyTheSame(copyRect, currentBox, .05));
1269         if (isBetterChoice) {
1270             switch (handlePosition) {
1271             case SelectionHandlePosition::Top:
1272             case SelectionHandlePosition::Bottom:
1273                 isBetterChoice = (copyRect.height() > currentBox.height());
1274                 break;
1275             case SelectionHandlePosition::Right:
1276             case SelectionHandlePosition::Left:
1277                 isBetterChoice = (copyRect.width() > currentBox.width());
1278                 break;
1279             }
1280
1281         }
1282
1283         if (bestRange && isBetterChoice) {
1284             // Furtherore, is it smaller than the best we've found so far?
1285             switch (handlePosition) {
1286             case SelectionHandlePosition::Top:
1287             case SelectionHandlePosition::Bottom:
1288                 isBetterChoice = (copyRect.height() < bestRect.height());
1289                 break;
1290             case SelectionHandlePosition::Right:
1291             case SelectionHandlePosition::Left:
1292                 isBetterChoice = (copyRect.width() < bestRect.width());
1293                 break;
1294             }
1295         }
1296
1297         if (isBetterChoice) {
1298             bestRange = newRange;
1299             bestRect = copyRect;
1300         }
1301     }
1302
1303     if (bestRange)
1304         return bestRange;
1305
1306     return currentRange;
1307 }
1308
1309 PassRefPtr<Range> WebPage::contractedRangeFromHandle(Range* currentRange, SelectionHandlePosition handlePosition, SelectionFlags& flags)
1310 {
1311     // Shrinking with a base and extent will always give better results. If we only have a single element,
1312     // see if we can break that down to a base and extent. Shrinking base and extent is comparatively straightforward.
1313     // Shrinking down to another element is unlikely to move just one edge, but we can try that as a fallback.
1314
1315     IntRect currentBox = selectionBoxForRange(currentRange);
1316     IntPoint edgeCenter = computeEdgeCenter(currentBox, handlePosition);
1317     flags = IsBlockSelection;
1318
1319     float maxDistance;
1320
1321     switch (handlePosition) {
1322     case SelectionHandlePosition::Top:
1323     case SelectionHandlePosition::Bottom:
1324         maxDistance = currentBox.height();
1325         break;
1326     case SelectionHandlePosition::Right:
1327     case SelectionHandlePosition::Left:
1328         maxDistance = currentBox.width();
1329         break;
1330     }
1331
1332     const float multiple = powf(maxDistance - 1, 1.0/(maxHitTests - 1));
1333     float distance = 1;
1334     RefPtr<Range> bestRange;
1335     IntRect bestRect;
1336
1337     while (distance < maxDistance) {
1338         if (bestRange) {
1339             float shrankDistance;
1340             switch (handlePosition) {
1341             case SelectionHandlePosition::Top:
1342             case SelectionHandlePosition::Bottom:
1343                 shrankDistance = abs(currentBox.height() - bestRect.height());
1344                 break;
1345             case SelectionHandlePosition::Right:
1346             case SelectionHandlePosition::Left:
1347                 shrankDistance = abs(currentBox.width() - bestRect.width());
1348                 break;
1349             }
1350             if (shrankDistance > distance) {
1351                 // Certainly not going to do any better than that.
1352                 break;
1353             }
1354         }
1355
1356         IntPoint testPoint = edgeCenter;
1357         switch (handlePosition) {
1358         case SelectionHandlePosition::Top:
1359             testPoint.move(0, distance);
1360             break;
1361         case SelectionHandlePosition::Right:
1362             testPoint.move(-distance, 0);
1363             break;
1364         case SelectionHandlePosition::Bottom:
1365             testPoint.move(0, -distance);
1366             break;
1367         case SelectionHandlePosition::Left:
1368             testPoint.move(distance, 0);
1369             break;
1370         }
1371
1372         distance *= multiple;
1373
1374         RefPtr<Range> newRange = rangeForBlockAtPoint(testPoint);
1375         if (!newRange || &newRange->ownerDocument() != &currentRange->ownerDocument())
1376             continue;
1377
1378         if (handlePosition == SelectionHandlePosition::Top || handlePosition == SelectionHandlePosition::Left)
1379             newRange = Range::create(newRange->startContainer()->document(), newRange->endPosition(), currentRange->endPosition());
1380         else
1381             newRange = Range::create(newRange->startContainer()->document(), currentRange->startPosition(), newRange->startPosition());
1382
1383         IntRect copyRect = selectionBoxForRange(newRange.get());
1384         if (copyRect.isEmpty()) {
1385             // If the new range is an empty rectangle, we try the block at the current point
1386             // and see if that has a rectangle that is a better choice.
1387             newRange = rangeForBlockAtPoint(testPoint);
1388             copyRect = selectionBoxForRange(newRange.get());
1389         }
1390         bool isBetterChoice;
1391         switch (handlePosition) {
1392         case SelectionHandlePosition::Top:
1393         case SelectionHandlePosition::Bottom:
1394             isBetterChoice = (copyRect.height() < currentBox.height());
1395             break;
1396         case SelectionHandlePosition::Left:
1397         case SelectionHandlePosition::Right:
1398             isBetterChoice = (copyRect.width() > bestRect.width());
1399             break;
1400         }
1401
1402         isBetterChoice = isBetterChoice && !areRangesEqual(newRange.get(), currentRange);
1403         if (bestRange && isBetterChoice) {
1404             switch (handlePosition) {
1405             case SelectionHandlePosition::Top:
1406             case SelectionHandlePosition::Bottom:
1407                 isBetterChoice = (copyRect.height() > bestRect.height());
1408                 break;
1409             case SelectionHandlePosition::Left:
1410             case SelectionHandlePosition::Right:
1411                 isBetterChoice = (copyRect.width() > bestRect.width());
1412                 break;
1413             }
1414         }
1415         if (isBetterChoice) {
1416             bestRange = newRange;
1417             bestRect = copyRect;
1418         }
1419
1420     }
1421
1422     if (!bestRange)
1423         bestRange = currentRange;
1424     
1425     // If we can shrink down to text only, the only reason we wouldn't is that
1426     // there are multiple sub-element blocks beneath us.  If we didn't find
1427     // multiple sub-element blocks, don't shrink to a sub-element block.
1428
1429     Node* node = bestRange->commonAncestorContainer(ASSERT_NO_EXCEPTION);
1430     if (!node->isElementNode())
1431         node = node->parentElement();
1432
1433     RenderObject* renderer = node->renderer();
1434     if (renderer && renderer->childrenInline() && (is<RenderBlock>(*renderer) && !downcast<RenderBlock>(*renderer).inlineElementContinuation()) && !renderer->isTable())
1435         flags = None;
1436
1437     return bestRange;
1438 }
1439
1440 void WebPage::computeExpandAndShrinkThresholdsForHandle(const IntPoint& point, SelectionHandlePosition handlePosition, float& growThreshold, float& shrinkThreshold)
1441 {
1442     Frame& frame = m_page->focusController().focusedOrMainFrame();
1443     RefPtr<Range> currentRange = m_currentBlockSelection ? m_currentBlockSelection.get() : frame.selection().selection().toNormalizedRange();
1444
1445     if (!currentRange)
1446         return;
1447
1448     RefPtr<Range> expandedRange = expandedRangeFromHandle(currentRange.get(), handlePosition);
1449     SelectionFlags flags;
1450     RefPtr<Range> contractedRange = contractedRangeFromHandle(currentRange.get(), handlePosition, flags);
1451
1452     IntRect currentBounds = selectionBoxForRange(currentRange.get());
1453     IntRect expandedBounds = selectionBoxForRange(expandedRange.get());
1454     IntRect contractedBounds = selectionBoxForRange(contractedRange.get());
1455
1456     float current;
1457     float expanded;
1458     float contracted;
1459     float maxThreshold;
1460     float minThreshold;
1461
1462     switch (handlePosition) {
1463     case SelectionHandlePosition::Top: {
1464         current = currentBounds.y();
1465         expanded = expandedBounds.y();
1466         contracted = contractedBounds.y();
1467         maxThreshold = FLT_MIN;
1468         minThreshold = FLT_MAX;
1469         break;
1470     }
1471     case SelectionHandlePosition::Right: {
1472         current = currentBounds.maxX();
1473         expanded = expandedBounds.maxX();
1474         contracted = contractedBounds.maxX();
1475         maxThreshold = FLT_MAX;
1476         minThreshold = FLT_MIN;
1477         break;
1478     }
1479     case SelectionHandlePosition::Bottom: {
1480         current = currentBounds.maxY();
1481         expanded = expandedBounds.maxY();
1482         contracted = contractedBounds.maxY();
1483         maxThreshold = FLT_MAX;
1484         minThreshold = FLT_MIN;
1485         break;
1486     }
1487     case SelectionHandlePosition::Left: {
1488         current = currentBounds.x();
1489         expanded = expandedBounds.x();
1490         contracted = contractedBounds.x();
1491         maxThreshold = FLT_MIN;
1492         minThreshold = FLT_MAX;
1493         break;
1494     }
1495     }
1496
1497     static const float fractionToGrow = 0.3;
1498
1499     growThreshold = current + (expanded - current) * fractionToGrow;
1500     shrinkThreshold = current + (contracted - current) * (1 - fractionToGrow);
1501     if (areRangesEqual(expandedRange.get(), currentRange.get()))
1502         growThreshold = maxThreshold;
1503
1504     if (flags & IsBlockSelection && areRangesEqual(contractedRange.get(), currentRange.get()))
1505         shrinkThreshold = minThreshold;
1506 }
1507
1508 static inline bool shouldExpand(SelectionHandlePosition handlePosition, const IntRect& rect, const IntPoint& point)
1509 {
1510     switch (handlePosition) {
1511     case SelectionHandlePosition::Top:
1512         return (point.y() < rect.y());
1513     case SelectionHandlePosition::Left:
1514         return (point.x() < rect.x());
1515     case SelectionHandlePosition::Right:
1516         return (point.x() > rect.maxX());
1517     case SelectionHandlePosition::Bottom:
1518         return (point.y() > rect.maxY());
1519     }
1520 }
1521
1522 PassRefPtr<WebCore::Range> WebPage::changeBlockSelection(const IntPoint& point, SelectionHandlePosition handlePosition, float& growThreshold, float& shrinkThreshold, SelectionFlags& flags)
1523 {
1524     Frame& frame = m_page->focusController().focusedOrMainFrame();
1525     RefPtr<Range> currentRange = m_currentBlockSelection ? m_currentBlockSelection.get() : frame.selection().selection().toNormalizedRange();
1526     if (!currentRange)
1527         return nullptr;
1528     RefPtr<Range> newRange = shouldExpand(handlePosition, selectionBoxForRange(currentRange.get()), point) ? expandedRangeFromHandle(currentRange.get(), handlePosition) : contractedRangeFromHandle(currentRange.get(), handlePosition, flags);
1529
1530     if (newRange) {
1531         m_currentBlockSelection = newRange;
1532         frame.selection().setSelectedRange(newRange.get(), VP_DEFAULT_AFFINITY, true);
1533     }
1534
1535     computeExpandAndShrinkThresholdsForHandle(point, handlePosition, growThreshold, shrinkThreshold);
1536     return newRange;
1537 }
1538
1539 void WebPage::updateBlockSelectionWithTouch(const IntPoint& point, uint32_t touch, uint32_t handlePosition)
1540 {
1541     Frame& frame = m_page->focusController().focusedOrMainFrame();
1542     IntPoint adjustedPoint = frame.view()->rootViewToContents(point);
1543
1544     float growThreshold = 0;
1545     float shrinkThreshold = 0;
1546     SelectionFlags flags = IsBlockSelection;
1547
1548     switch (static_cast<SelectionTouch>(touch)) {
1549     case SelectionTouch::Started:
1550         computeExpandAndShrinkThresholdsForHandle(adjustedPoint, static_cast<SelectionHandlePosition>(handlePosition), growThreshold, shrinkThreshold);
1551         break;
1552     case SelectionTouch::Ended:
1553         break;
1554     case SelectionTouch::Moved:
1555         changeBlockSelection(adjustedPoint, static_cast<SelectionHandlePosition>(handlePosition), growThreshold, shrinkThreshold, flags);
1556         break;
1557     default:
1558         return;
1559     }
1560
1561     send(Messages::WebPageProxy::DidUpdateBlockSelectionWithTouch(touch, static_cast<uint32_t>(flags), growThreshold, shrinkThreshold));
1562 }
1563
1564 void WebPage::clearSelection()
1565 {
1566     m_currentBlockSelection = nullptr;
1567     m_page->focusController().focusedOrMainFrame().selection().clear();
1568 }
1569
1570 void WebPage::updateSelectionWithTouches(const IntPoint& point, uint32_t touches, bool baseIsStart, uint64_t callbackID)
1571 {
1572     Frame& frame = m_page->focusController().focusedOrMainFrame();
1573     VisiblePosition position = frame.visiblePositionForPoint(frame.view()->rootViewToContents(point));
1574     if (position.isNull()) {
1575         send(Messages::WebPageProxy::TouchesCallback(point, touches, callbackID));
1576         return;
1577     }
1578
1579     RefPtr<Range> range;
1580     VisiblePosition result;
1581     
1582     switch (static_cast<SelectionTouch>(touches)) {
1583     case SelectionTouch::Started:
1584     case SelectionTouch::EndedNotMoving:
1585         break;
1586     
1587     case SelectionTouch::Ended:
1588         if (frame.selection().selection().isContentEditable()) {
1589             result = closestWordBoundaryForPosition(position);
1590             if (result.isNotNull())
1591                 range = Range::create(*frame.document(), result, result);
1592         } else
1593             range = rangeForPosition(&frame, position, baseIsStart);
1594         break;
1595
1596     case SelectionTouch::EndedMovingForward:
1597         range = rangeAtWordBoundaryForPosition(&frame, position, baseIsStart, DirectionForward);
1598         break;
1599         
1600     case SelectionTouch::EndedMovingBackward:
1601         range = rangeAtWordBoundaryForPosition(&frame, position, baseIsStart, DirectionBackward);
1602         break;
1603
1604     case SelectionTouch::Moved:
1605         range = rangeForPosition(&frame, position, baseIsStart);
1606         break;
1607     }
1608     if (range)
1609         frame.selection().setSelectedRange(range.get(), position.affinity(), true);
1610
1611     send(Messages::WebPageProxy::TouchesCallback(point, touches, callbackID));
1612 }
1613
1614 void WebPage::selectWithTwoTouches(const WebCore::IntPoint& from, const WebCore::IntPoint& to, uint32_t gestureType, uint32_t gestureState, uint64_t callbackID)
1615 {
1616     Frame& frame = m_page->focusController().focusedOrMainFrame();
1617     VisiblePosition fromPosition = frame.visiblePositionForPoint(frame.view()->rootViewToContents(from));
1618     VisiblePosition toPosition = frame.visiblePositionForPoint(frame.view()->rootViewToContents(to));
1619     RefPtr<Range> range;
1620     if (fromPosition.isNotNull() && toPosition.isNotNull()) {
1621         if (fromPosition < toPosition)
1622             range = Range::create(*frame.document(), fromPosition, toPosition);
1623         else
1624             range = Range::create(*frame.document(), toPosition, fromPosition);
1625         frame.selection().setSelectedRange(range.get(), fromPosition.affinity(), true);
1626     }
1627
1628     // We can use the same callback for the gestures with one point.
1629     send(Messages::WebPageProxy::GestureCallback(from, gestureType, gestureState, 0, callbackID));
1630 }
1631
1632 void WebPage::extendSelection(uint32_t granularity)
1633 {
1634     Frame& frame = m_page->focusController().focusedOrMainFrame();
1635     // For the moment we handle only WordGranularity.
1636     if (granularity != WordGranularity || !frame.selection().isCaret())
1637         return;
1638
1639     VisiblePosition position = frame.selection().selection().start();
1640     frame.selection().setSelectedRange(wordRangeFromPosition(position).get(), position.affinity(), true);
1641 }
1642
1643 void WebPage::selectWordBackward()
1644 {
1645     Frame& frame = m_page->focusController().focusedOrMainFrame();
1646     if (!frame.selection().isCaret())
1647         return;
1648
1649     VisiblePosition position = frame.selection().selection().start();
1650     VisiblePosition startPosition = positionOfNextBoundaryOfGranularity(position, WordGranularity, DirectionBackward);
1651     if (startPosition.isNotNull() && startPosition != position)
1652         frame.selection().setSelectedRange(Range::create(*frame.document(), startPosition, position).ptr(), position.affinity(), true);
1653 }
1654
1655 void WebPage::moveSelectionByOffset(int32_t offset, uint64_t callbackID)
1656 {
1657     Frame& frame = m_page->focusController().focusedOrMainFrame();
1658     
1659     VisiblePosition startPosition = frame.selection().selection().end();
1660     if (startPosition.isNull())
1661         return;
1662     SelectionDirection direction = offset < 0 ? DirectionBackward : DirectionForward;
1663     VisiblePosition position = startPosition;
1664     for (int i = 0; i < abs(offset); ++i) {
1665         position = positionOfNextBoundaryOfGranularity(position, CharacterGranularity, direction);
1666         if (position.isNull())
1667             break;
1668     }
1669     if (position.isNotNull() && startPosition != position)
1670         frame.selection().setSelectedRange(Range::create(*frame.document(), position, position).ptr(), position.affinity(), true);
1671     send(Messages::WebPageProxy::VoidCallback(callbackID));
1672 }
1673
1674 VisiblePosition WebPage::visiblePositionInFocusedNodeForPoint(Frame& frame, const IntPoint& point)
1675 {
1676     IntPoint adjustedPoint(frame.view()->rootViewToContents(point));
1677     IntPoint constrainedPoint = m_assistedNode ? constrainPoint(adjustedPoint, &frame, m_assistedNode.get()) : adjustedPoint;
1678     return frame.visiblePositionForPoint(constrainedPoint);
1679 }
1680
1681 void WebPage::selectPositionAtPoint(const WebCore::IntPoint& point, uint64_t callbackID)
1682 {
1683     Frame& frame = m_page->focusController().focusedOrMainFrame();
1684     VisiblePosition position = visiblePositionInFocusedNodeForPoint(frame, point);
1685     
1686     if (position.isNotNull())
1687         frame.selection().setSelectedRange(Range::create(*frame.document(), position, position).ptr(), position.affinity(), true);
1688     send(Messages::WebPageProxy::VoidCallback(callbackID));
1689 }
1690
1691 void WebPage::selectPositionAtBoundaryWithDirection(const WebCore::IntPoint& point, uint32_t granularity, uint32_t direction, uint64_t callbackID)
1692 {
1693     Frame& frame = m_page->focusController().focusedOrMainFrame();
1694     VisiblePosition position = visiblePositionInFocusedNodeForPoint(frame, point);
1695
1696     if (position.isNotNull()) {
1697         position = positionOfNextBoundaryOfGranularity(position, static_cast<WebCore::TextGranularity>(granularity), static_cast<SelectionDirection>(direction));
1698         if (position.isNotNull())
1699             frame.selection().setSelectedRange(Range::create(*frame.document(), position, position).ptr(), UPSTREAM, true);
1700     }
1701     send(Messages::WebPageProxy::VoidCallback(callbackID));
1702 }
1703
1704 void WebPage::moveSelectionAtBoundaryWithDirection(uint32_t granularity, uint32_t direction, uint64_t callbackID)
1705 {
1706     Frame& frame = m_page->focusController().focusedOrMainFrame();
1707     
1708     if (!frame.selection().selection().isNone()) {
1709         bool isForward = (direction == DirectionForward || direction == DirectionRight);
1710         VisiblePosition position = (isForward) ? frame.selection().selection().visibleEnd() : frame.selection().selection().visibleStart();
1711         position = positionOfNextBoundaryOfGranularity(position, static_cast<WebCore::TextGranularity>(granularity), static_cast<SelectionDirection>(direction));
1712         if (position.isNotNull())
1713             frame.selection().setSelectedRange(Range::create(*frame.document(), position, position).ptr(), isForward? UPSTREAM : DOWNSTREAM, true);
1714     }
1715     send(Messages::WebPageProxy::VoidCallback(callbackID));
1716 }
1717
1718 void WebPage::selectTextWithGranularityAtPoint(const WebCore::IntPoint& point, uint32_t granularity, uint64_t callbackID)
1719 {
1720     Frame& frame = m_page->focusController().focusedOrMainFrame();
1721     VisiblePosition position = visiblePositionInFocusedNodeForPoint(frame, point);
1722
1723     RefPtr<Range> range;
1724     switch (static_cast<WebCore::TextGranularity>(granularity)) {
1725     case WordGranularity:
1726         range = wordRangeFromPosition(position);
1727         break;
1728     case SentenceGranularity:
1729         range = enclosingTextUnitOfGranularity(position, SentenceGranularity, DirectionForward);
1730         break;
1731     case ParagraphGranularity:
1732         range = enclosingTextUnitOfGranularity(position, ParagraphGranularity, DirectionForward);
1733         break;
1734     case DocumentGranularity:
1735         frame.selection().selectAll();
1736         break;
1737     default:
1738         break;
1739     }
1740     if (range)
1741         frame.selection().setSelectedRange(range.get(), UPSTREAM, true);
1742     send(Messages::WebPageProxy::VoidCallback(callbackID));
1743 }
1744
1745 void WebPage::beginSelectionInDirection(uint32_t direction, uint64_t callbackID)
1746 {
1747     m_selectionAnchor = (static_cast<SelectionDirection>(direction) == DirectionLeft) ? Start : End;
1748     send(Messages::WebPageProxy::UnsignedCallback(m_selectionAnchor == Start, callbackID));
1749 }
1750     
1751 void WebPage::updateSelectionWithExtentPoint(const WebCore::IntPoint& point, uint64_t callbackID)
1752 {
1753     Frame& frame = m_page->focusController().focusedOrMainFrame();
1754     VisiblePosition position = visiblePositionInFocusedNodeForPoint(frame, point);
1755
1756     if (position.isNull()) {
1757         send(Messages::WebPageProxy::UnsignedCallback(false, callbackID));
1758         return;
1759     }
1760
1761     RefPtr<Range> range;
1762     VisiblePosition selectionStart;
1763     VisiblePosition selectionEnd;
1764     
1765     if (m_selectionAnchor == Start) {
1766         selectionStart = frame.selection().selection().visibleStart();
1767         selectionEnd = position;
1768
1769         if (position <= selectionStart) {
1770             selectionStart = selectionStart.previous();
1771             selectionEnd = frame.selection().selection().visibleEnd();
1772             m_selectionAnchor = End;
1773         }
1774     } else {
1775         selectionStart = position;
1776         selectionEnd = frame.selection().selection().visibleEnd();
1777         
1778         if (position >= selectionEnd) {
1779             selectionStart = frame.selection().selection().visibleStart();
1780             selectionEnd = selectionEnd.next();
1781             m_selectionAnchor = Start;
1782         }
1783     }
1784     
1785     if (selectionStart.isNotNull() && selectionEnd.isNotNull())
1786         range = Range::create(*frame.document(), selectionStart, selectionEnd);
1787
1788     if (range)
1789         frame.selection().setSelectedRange(range.get(), UPSTREAM, true);
1790
1791     send(Messages::WebPageProxy::UnsignedCallback(m_selectionAnchor == Start, callbackID));
1792 }
1793
1794 void WebPage::convertSelectionRectsToRootView(FrameView* view, Vector<SelectionRect>& selectionRects)
1795 {
1796     for (size_t i = 0; i < selectionRects.size(); ++i) {
1797         SelectionRect& currentRect = selectionRects[i];
1798         currentRect.setRect(view->contentsToRootView(currentRect.rect()));
1799     }
1800 }
1801
1802 void WebPage::requestDictationContext(uint64_t callbackID)
1803 {
1804     Frame& frame = m_page->focusController().focusedOrMainFrame();
1805     VisiblePosition startPosition = frame.selection().selection().start();
1806     VisiblePosition endPosition = frame.selection().selection().end();
1807     const unsigned dictationContextWordCount = 5;
1808
1809     String selectedText;
1810     if (frame.selection().isRange())
1811         selectedText = plainTextReplacingNoBreakSpace(frame.selection().selection().toNormalizedRange().get());
1812
1813     String contextBefore;
1814     if (startPosition != startOfEditableContent(startPosition)) {
1815         VisiblePosition currentPosition = startPosition;
1816         VisiblePosition lastPosition = startPosition;
1817         for (unsigned i = 0; i < dictationContextWordCount; ++i) {
1818             currentPosition = startOfWord(positionOfNextBoundaryOfGranularity(lastPosition, WordGranularity, DirectionBackward));
1819             if (currentPosition.isNull())
1820                 break;
1821             lastPosition = currentPosition;
1822         }
1823         if (lastPosition.isNotNull() && lastPosition != startPosition)
1824             contextBefore = plainTextReplacingNoBreakSpace(Range::create(*frame.document(), lastPosition, startPosition).ptr());
1825     }
1826
1827     String contextAfter;
1828     if (endPosition != endOfEditableContent(endPosition)) {
1829         VisiblePosition currentPosition = endPosition;
1830         VisiblePosition lastPosition = endPosition;
1831         for (unsigned i = 0; i < dictationContextWordCount; ++i) {
1832             currentPosition = endOfWord(positionOfNextBoundaryOfGranularity(lastPosition, WordGranularity, DirectionForward));
1833             if (currentPosition.isNull())
1834                 break;
1835             lastPosition = currentPosition;
1836         }
1837         if (lastPosition.isNotNull() && lastPosition != endPosition)
1838             contextAfter = plainTextReplacingNoBreakSpace(Range::create(*frame.document(), endPosition, lastPosition).ptr());
1839     }
1840
1841     send(Messages::WebPageProxy::DictationContextCallback(selectedText, contextBefore, contextAfter, callbackID));
1842 }
1843
1844 void WebPage::replaceSelectedText(const String& oldText, const String& newText)
1845 {
1846     Frame& frame = m_page->focusController().focusedOrMainFrame();
1847     RefPtr<Range> wordRange = frame.selection().isCaret() ? wordRangeFromPosition(frame.selection().selection().start()) : frame.selection().toNormalizedRange();
1848     if (plainTextReplacingNoBreakSpace(wordRange.get()) != oldText)
1849         return;
1850     
1851     frame.editor().setIgnoreCompositionSelectionChange(true);
1852     frame.selection().setSelectedRange(wordRange.get(), UPSTREAM, true);
1853     frame.editor().insertText(newText, 0);
1854     frame.editor().setIgnoreCompositionSelectionChange(false);
1855 }
1856
1857 void WebPage::replaceDictatedText(const String& oldText, const String& newText)
1858 {
1859     Frame& frame = m_page->focusController().focusedOrMainFrame();
1860     if (frame.selection().isNone())
1861         return;
1862     
1863     if (frame.selection().isRange()) {
1864         frame.editor().deleteSelectionWithSmartDelete(false);
1865         return;
1866     }
1867     VisiblePosition position = frame.selection().selection().start();
1868     for (size_t i = 0; i < oldText.length(); ++i)
1869         position = position.previous();
1870     if (position.isNull())
1871         position = startOfDocument(static_cast<Node*>(frame.document()->documentElement()));
1872     RefPtr<Range> range = Range::create(*frame.document(), position, frame.selection().selection().start());
1873
1874     if (plainTextReplacingNoBreakSpace(range.get()) != oldText)
1875         return;
1876
1877     // We don't want to notify the client that the selection has changed until we are done inserting the new text.
1878     frame.editor().setIgnoreCompositionSelectionChange(true);
1879     frame.selection().setSelectedRange(range.get(), UPSTREAM, true);
1880     frame.editor().insertText(newText, 0);
1881     frame.editor().setIgnoreCompositionSelectionChange(false);
1882 }
1883
1884 void WebPage::requestAutocorrectionData(const String& textForAutocorrection, uint64_t callbackID)
1885 {
1886     Frame& frame = m_page->focusController().focusedOrMainFrame();
1887     if (!frame.selection().isCaret()) {
1888         send(Messages::WebPageProxy::AutocorrectionDataCallback(Vector<FloatRect>(), String(), 0, 0, callbackID));
1889         return;
1890     }
1891
1892     VisiblePosition position = frame.selection().selection().start();
1893     RefPtr<Range> range = wordRangeFromPosition(position);
1894     if (!range) {
1895         send(Messages::WebPageProxy::AutocorrectionDataCallback(Vector<FloatRect>(), String(), 0, 0, callbackID));
1896         return;
1897     }
1898
1899     String textForRange = plainTextReplacingNoBreakSpace(range.get());
1900     const unsigned maxSearchAttempts = 5;
1901     for (size_t i = 0;  i < maxSearchAttempts && textForRange != textForAutocorrection; ++i)
1902     {
1903         position = range->startPosition().previous();
1904         if (position.isNull() || position == range->startPosition())
1905             break;
1906         range = Range::create(*frame.document(), wordRangeFromPosition(position)->startPosition(), range->endPosition());
1907         textForRange = plainTextReplacingNoBreakSpace(range.get());
1908     }
1909
1910     Vector<SelectionRect> selectionRects;
1911     if (textForRange == textForAutocorrection)
1912         range->collectSelectionRects(selectionRects);
1913
1914     Vector<FloatRect> rectsForText;
1915     rectsForText.resize(selectionRects.size());
1916
1917     convertSelectionRectsToRootView(frame.view(), selectionRects);
1918     for (size_t i = 0; i < selectionRects.size(); i++)
1919         rectsForText[i] = selectionRects[i].rect();
1920
1921     bool multipleFonts = false;
1922     CTFontRef font = nil;
1923     if (auto* coreFont = frame.editor().fontForSelection(multipleFonts))
1924         font = coreFont->getCTFont();
1925
1926     CGFloat fontSize = CTFontGetSize(font);
1927     uint64_t fontTraits = CTFontGetSymbolicTraits(font);
1928     RetainPtr<NSString> fontName = adoptNS((NSString *)CTFontCopyFamilyName(font));
1929     send(Messages::WebPageProxy::AutocorrectionDataCallback(rectsForText, fontName.get(), fontSize, fontTraits, callbackID));
1930 }
1931
1932 void WebPage::applyAutocorrection(const String& correction, const String& originalText, uint64_t callbackID)
1933 {
1934     bool correctionApplied;
1935     syncApplyAutocorrection(correction, originalText, correctionApplied);
1936     send(Messages::WebPageProxy::StringCallback(correctionApplied ? correction : String(), callbackID));
1937 }
1938
1939 void WebPage::executeEditCommandWithCallback(const String& commandName, uint64_t callbackID)
1940 {
1941     executeEditCommand(commandName);
1942     if (commandName == "toggleBold" || commandName == "toggleItalic" || commandName == "toggleUnderline")
1943         send(Messages::WebPageProxy::EditorStateChanged(editorState()));
1944     send(Messages::WebPageProxy::VoidCallback(callbackID));
1945 }
1946
1947 std::chrono::milliseconds WebPage::eventThrottlingDelay() const
1948 {
1949     if (m_isInStableState || m_estimatedLatency <= std::chrono::milliseconds(1000 / 60))
1950         return std::chrono::milliseconds::zero();
1951
1952     return std::chrono::milliseconds(std::min<std::chrono::milliseconds::rep>(m_estimatedLatency.count() * 2, 1000));
1953 }
1954
1955 void WebPage::syncApplyAutocorrection(const String& correction, const String& originalText, bool& correctionApplied)
1956 {
1957     RefPtr<Range> range;
1958     correctionApplied = false;
1959     Frame& frame = m_page->focusController().focusedOrMainFrame();
1960     if (!frame.selection().isCaret())
1961         return;
1962     VisiblePosition position = frame.selection().selection().start();
1963     
1964     range = wordRangeFromPosition(position);
1965     String textForRange = plainTextReplacingNoBreakSpace(range.get());
1966     if (textForRange != originalText) {
1967         for (size_t i = 0; i < originalText.length(); ++i)
1968             position = position.previous();
1969         if (position.isNull())
1970             position = startOfDocument(static_cast<Node*>(frame.document()->documentElement()));
1971         range = Range::create(*frame.document(), position, frame.selection().selection().start());
1972         if (range)
1973             textForRange = (range) ? plainTextReplacingNoBreakSpace(range.get()) : emptyString();
1974         unsigned loopCount = 0;
1975         const unsigned maxPositionsAttempts = 10;
1976         while (textForRange.length() && textForRange.length() > originalText.length() && loopCount < maxPositionsAttempts) {
1977             position = position.next();
1978             if (position.isNotNull() && position >= frame.selection().selection().start())
1979                 range = NULL;
1980             else
1981                 range = Range::create(*frame.document(), position, frame.selection().selection().start());
1982             textForRange = (range) ? plainTextReplacingNoBreakSpace(range.get()) : emptyString();
1983             loopCount++;
1984         }
1985     }
1986     if (textForRange != originalText) {
1987         correctionApplied = false;
1988         return;
1989     }
1990     
1991     frame.selection().setSelectedRange(range.get(), UPSTREAM, true);
1992     if (correction.length())
1993         frame.editor().insertText(correction, 0);
1994     else
1995         frame.editor().deleteWithDirection(DirectionBackward, CharacterGranularity, false, true);
1996     correctionApplied = true;
1997 }
1998
1999 static void computeAutocorrectionContext(Frame& frame, String& contextBefore, String& markedText, String& selectedText, String& contextAfter, uint64_t& location, uint64_t& length)
2000 {
2001     RefPtr<Range> range;
2002     VisiblePosition startPosition = frame.selection().selection().start();
2003     VisiblePosition endPosition = frame.selection().selection().end();
2004     location = NSNotFound;
2005     length = 0;
2006     const unsigned minContextWordCount = 3;
2007     const unsigned minContextLenght = 12;
2008     const unsigned maxContextLength = 30;
2009
2010     if (frame.selection().isRange())
2011         selectedText = plainTextReplacingNoBreakSpace(frame.selection().selection().toNormalizedRange().get());
2012
2013     if (frame.editor().hasComposition()) {
2014         range = Range::create(*frame.document(), frame.editor().compositionRange()->startPosition(), startPosition);
2015         String markedTextBefore;
2016         if (range)
2017             markedTextBefore = plainTextReplacingNoBreakSpace(range.get());
2018         range = Range::create(*frame.document(), endPosition, frame.editor().compositionRange()->endPosition());
2019         String markedTextAfter;
2020         if (range)
2021             markedTextAfter = plainTextReplacingNoBreakSpace(range.get());
2022         markedText = markedTextBefore + selectedText + markedTextAfter;
2023         if (!markedText.isEmpty()) {
2024             location = markedTextBefore.length();
2025             length = selectedText.length();
2026         }
2027     } else {
2028         if (startPosition != startOfEditableContent(startPosition)) {
2029             VisiblePosition currentPosition = startPosition;
2030             VisiblePosition previousPosition;
2031             unsigned totalContextLength = 0;
2032             for (unsigned i = 0; i < minContextWordCount; ++i) {
2033                 if (contextBefore.length() >= minContextLenght)
2034                     break;
2035                 previousPosition = startOfWord(positionOfNextBoundaryOfGranularity(currentPosition, WordGranularity, DirectionBackward));
2036                 if (previousPosition.isNull())
2037                     break;
2038                 String currentWord = plainTextReplacingNoBreakSpace(Range::create(*frame.document(), previousPosition, currentPosition).ptr());
2039                 totalContextLength += currentWord.length();
2040                 if (totalContextLength >= maxContextLength)
2041                     break;
2042                 currentPosition = previousPosition;
2043             }
2044             if (currentPosition.isNotNull() && currentPosition != startPosition) {
2045                 contextBefore = plainTextReplacingNoBreakSpace(Range::create(*frame.document(), currentPosition, startPosition).ptr());
2046                 if (atBoundaryOfGranularity(currentPosition, ParagraphGranularity, DirectionBackward))
2047                     contextBefore = ASCIILiteral("\n ") + contextBefore;
2048             }
2049         }
2050
2051         if (endPosition != endOfEditableContent(endPosition)) {
2052             VisiblePosition nextPosition;
2053             if (!atBoundaryOfGranularity(endPosition, WordGranularity, DirectionForward) && withinTextUnitOfGranularity(endPosition, WordGranularity, DirectionForward))
2054                 nextPosition = positionOfNextBoundaryOfGranularity(endPosition, WordGranularity, DirectionForward);
2055             if (nextPosition.isNotNull())
2056                 contextAfter = plainTextReplacingNoBreakSpace(Range::create(*frame.document(), endPosition, nextPosition).ptr());
2057         }
2058     }
2059 }
2060
2061 void WebPage::requestAutocorrectionContext(uint64_t callbackID)
2062 {
2063     String contextBefore;
2064     String contextAfter;
2065     String selectedText;
2066     String markedText;
2067     uint64_t location;
2068     uint64_t length;
2069
2070     computeAutocorrectionContext(m_page->focusController().focusedOrMainFrame(), contextBefore, markedText, selectedText, contextAfter, location, length);
2071
2072     send(Messages::WebPageProxy::AutocorrectionContextCallback(contextBefore, markedText, selectedText, contextAfter, location, length, callbackID));
2073 }
2074
2075 void WebPage::getAutocorrectionContext(String& contextBefore, String& markedText, String& selectedText, String& contextAfter, uint64_t& location, uint64_t& length)
2076 {
2077     computeAutocorrectionContext(m_page->focusController().focusedOrMainFrame(), contextBefore, markedText, selectedText, contextAfter, location, length);
2078 }
2079
2080 static Element* containingLinkElement(Element* element)
2081 {
2082     for (auto& currentElement : elementLineage(element)) {
2083         if (currentElement.isLink())
2084             return &currentElement;
2085     }
2086     return nullptr;
2087 }
2088
2089 void WebPage::getPositionInformation(const IntPoint& point, InteractionInformationAtPosition& info)
2090 {
2091     FloatPoint adjustedPoint;
2092     Node* hitNode = m_page->mainFrame().nodeRespondingToClickEvents(point, adjustedPoint);
2093
2094     info.point = point;
2095     info.nodeAtPositionIsAssistedNode = (hitNode == m_assistedNode);
2096     if (m_assistedNode) {
2097         Frame& frame = m_page->focusController().focusedOrMainFrame();
2098         if (frame.editor().hasComposition()) {
2099             const uint32_t kHitAreaWidth = 66;
2100             const uint32_t kHitAreaHeight = 66;
2101             FrameView& view = *frame.view();
2102             IntPoint adjustedPoint(view.rootViewToContents(point));
2103             IntPoint constrainedPoint = m_assistedNode ? constrainPoint(adjustedPoint, &frame, m_assistedNode.get()) : adjustedPoint;
2104             VisiblePosition position = frame.visiblePositionForPoint(constrainedPoint);
2105
2106             RefPtr<Range> compositionRange = frame.editor().compositionRange();
2107             if (position < compositionRange->startPosition())
2108                 position = compositionRange->startPosition();
2109             else if (position > compositionRange->endPosition())
2110                 position = compositionRange->endPosition();
2111             IntRect caretRect = view.contentsToRootView(position.absoluteCaretBounds());
2112             float deltaX = abs(caretRect.x() + (caretRect.width() / 2) - point.x());
2113             float deltaYFromTheTop = abs(caretRect.y() - point.y());
2114             float deltaYFromTheBottom = abs(caretRect.y() + caretRect.height() - point.y());
2115
2116             info.isNearMarkedText = !(deltaX > kHitAreaWidth || deltaYFromTheTop > kHitAreaHeight || deltaYFromTheBottom > kHitAreaHeight);
2117         }
2118     }
2119     bool elementIsLinkOrImage = false;
2120     if (hitNode) {
2121         info.clickableElementName = hitNode->nodeName();
2122
2123         Element* element = is<Element>(*hitNode) ? downcast<Element>(hitNode) : nullptr;
2124         if (element) {
2125             Element* linkElement = nullptr;
2126             if (element->renderer() && element->renderer()->isRenderImage()) {
2127                 elementIsLinkOrImage = true;
2128                 linkElement = containingLinkElement(element);
2129             } else if (element->isLink()) {
2130                 linkElement = element;
2131                 elementIsLinkOrImage = true;
2132             }
2133
2134             if (elementIsLinkOrImage) {
2135                 // Ensure that the image contains at most 600K pixels, so that it is not too big.
2136                 if (RefPtr<WebImage> snapshot = snapshotNode(*element, SnapshotOptionsShareable, 600 * 1024))
2137                     info.image = snapshot->bitmap();
2138             }
2139             if (linkElement)
2140                 info.url = [(NSURL *)linkElement->document().completeURL(stripLeadingAndTrailingHTMLSpaces(linkElement->getAttribute(HTMLNames::hrefAttr))) absoluteString];
2141             info.title = element->fastGetAttribute(HTMLNames::titleAttr).string();
2142             if (linkElement && info.title.isEmpty())
2143                 info.title = element->innerText();
2144             if (element->renderer()) {
2145                 info.bounds = element->renderer()->absoluteBoundingBoxRect(true);
2146                 info.touchCalloutEnabled = element->renderer()->style().touchCalloutEnabled();
2147             }
2148         }
2149     }
2150
2151     if (!elementIsLinkOrImage) {
2152         HitTestResult result = m_page->mainFrame().eventHandler().hitTestResultAtPoint((point), HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShadowContent | HitTestRequest::AllowChildFrameContent);
2153         hitNode = result.innerNode();
2154         // Hit test could return HTMLHtmlElement that has no renderer, if the body is smaller than the document.
2155         if (hitNode && hitNode->renderer()) {
2156             RenderObject* renderer = hitNode->renderer();
2157             m_page->focusController().setFocusedFrame(result.innerNodeFrame());
2158             info.bounds = renderer->absoluteBoundingBoxRect(true);
2159             // We don't want to select blocks that are larger than 97% of the visible area of the document.
2160             const static CGFloat factor = 0.97;
2161             info.isSelectable = renderer->style().userSelect() != SELECT_NONE && info.bounds.height() < result.innerNodeFrame()->view()->unobscuredContentRect().height() * factor;
2162         }
2163     }
2164 }
2165
2166 void WebPage::requestPositionInformation(const IntPoint& point)
2167 {
2168     InteractionInformationAtPosition info;
2169
2170     getPositionInformation(point, info);
2171     send(Messages::WebPageProxy::DidReceivePositionInformation(info));
2172 }
2173
2174 void WebPage::startInteractionWithElementAtPosition(const WebCore::IntPoint& point)
2175 {
2176     FloatPoint adjustedPoint;
2177     m_interactionNode = m_page->mainFrame().nodeRespondingToClickEvents(point, adjustedPoint);
2178 }
2179
2180 void WebPage::stopInteraction()
2181 {
2182     m_interactionNode = nullptr;
2183 }
2184
2185 void WebPage::performActionOnElement(uint32_t action)
2186 {
2187     if (!is<HTMLElement>(m_interactionNode.get()))
2188         return;
2189
2190     HTMLElement& element = downcast<HTMLElement>(*m_interactionNode);
2191     if (!element.renderer())
2192         return;
2193
2194     if (static_cast<SheetAction>(action) == SheetAction::Copy) {
2195         if (is<RenderImage>(*element.renderer())) {
2196             Element* linkElement = containingLinkElement(&element);
2197             if (!linkElement)
2198                 m_interactionNode->document().frame()->editor().writeImageToPasteboard(*Pasteboard::createForCopyAndPaste(), element, downcast<RenderImage>(*element.renderer()).cachedImage()->url(), String());
2199             else
2200                 m_interactionNode->document().frame()->editor().copyURL(linkElement->document().completeURL(stripLeadingAndTrailingHTMLSpaces(linkElement->fastGetAttribute(HTMLNames::hrefAttr))), linkElement->textContent());
2201         } else if (element.isLink()) {
2202             m_interactionNode->document().frame()->editor().copyURL(element.document().completeURL(stripLeadingAndTrailingHTMLSpaces(element.fastGetAttribute(HTMLNames::hrefAttr))), element.textContent());
2203         }
2204     } else if (static_cast<SheetAction>(action) == SheetAction::SaveImage) {
2205         if (!is<RenderImage>(*element.renderer()))
2206             return;
2207         CachedImage* cachedImage = downcast<RenderImage>(*element.renderer()).cachedImage();
2208         if (!cachedImage)
2209             return;
2210         RefPtr<SharedBuffer> buffer = cachedImage->resourceBuffer();
2211         if (!buffer)
2212             return;
2213         uint64_t bufferSize = buffer->size();
2214         RefPtr<SharedMemory> sharedMemoryBuffer = SharedMemory::allocate(bufferSize);
2215         memcpy(sharedMemoryBuffer->data(), buffer->data(), bufferSize);
2216         SharedMemory::Handle handle;
2217         sharedMemoryBuffer->createHandle(handle, SharedMemory::Protection::ReadOnly);
2218         send(Messages::WebPageProxy::SaveImageToLibrary(handle, bufferSize));
2219     }
2220 }
2221
2222 static inline bool isAssistableElement(Element& node)
2223 {
2224     if (is<HTMLSelectElement>(node))
2225         return true;
2226     if (is<HTMLTextAreaElement>(node))
2227         return !downcast<HTMLTextAreaElement>(node).isReadOnlyNode();
2228     if (is<HTMLInputElement>(node)) {
2229         HTMLInputElement& inputElement = downcast<HTMLInputElement>(node);
2230         // FIXME: This laundry list of types is not a good way to factor this. Need a suitable function on HTMLInputElement itself.
2231         return !inputElement.isReadOnlyNode() && (inputElement.isTextField() || inputElement.isDateField() || inputElement.isDateTimeLocalField() || inputElement.isMonthField() || inputElement.isTimeField());
2232     }
2233     return node.isContentEditable();
2234 }
2235
2236 static inline Element* nextAssistableElement(Node* startNode, Page& page, bool isForward)
2237 {
2238     if (!is<Element>(startNode))
2239         return nullptr;
2240
2241     RefPtr<KeyboardEvent> key = KeyboardEvent::create();
2242
2243     Element* nextElement = downcast<Element>(startNode);
2244     do {
2245         nextElement = isForward
2246             ? page.focusController().nextFocusableElement(FocusNavigationScope::focusNavigationScopeOf(&nextElement->document()), nextElement, key.get())
2247             : page.focusController().previousFocusableElement(FocusNavigationScope::focusNavigationScopeOf(&nextElement->document()), nextElement, key.get());
2248     } while (nextElement && !isAssistableElement(*nextElement));
2249
2250     return nextElement;
2251 }
2252
2253 static inline bool hasAssistableElement(Node* startNode, Page& page, bool isForward)
2254 {
2255     return nextAssistableElement(startNode, page, isForward);
2256 }
2257
2258 void WebPage::focusNextAssistedNode(bool isForward, uint64_t callbackID)
2259 {
2260     Element* nextElement = nextAssistableElement(m_assistedNode.get(), *m_page, isForward);
2261     m_userIsInteracting = true;
2262     if (nextElement)
2263         nextElement->focus();
2264     m_userIsInteracting = false;
2265     send(Messages::WebPageProxy::VoidCallback(callbackID));
2266 }
2267
2268 void WebPage::getAssistedNodeInformation(AssistedNodeInformation& information)
2269 {
2270     layoutIfNeeded();
2271
2272     // FIXME: This should return the selection rect, but when this is called at focus time
2273     // we don't have a selection yet. Using the last interaction location is a reasonable approximation for now.
2274     // FIXME: should the selection rect always be inside the elementRect?
2275     information.selectionRect = IntRect(m_lastInteractionLocation, IntSize(1, 1));
2276
2277     if (RenderObject* renderer = m_assistedNode->renderer()) {
2278         Frame& elementFrame = m_page->focusController().focusedOrMainFrame();
2279         information.elementRect = elementFrame.view()->contentsToRootView(renderer->absoluteBoundingBoxRect());
2280         information.nodeFontSize = renderer->style().fontDescription().computedSize();
2281
2282         bool inFixed = false;
2283         renderer->localToContainerPoint(FloatPoint(), nullptr, UseTransforms, &inFixed);
2284         information.insideFixedPosition = inFixed;
2285         
2286         if (inFixed && elementFrame.isMainFrame()) {
2287             FrameView* frameView = elementFrame.view();
2288             IntRect currentFixedPositionRect = frameView->customFixedPositionLayoutRect();
2289             frameView->setCustomFixedPositionLayoutRect(frameView->renderView()->documentRect());
2290             information.elementRect = frameView->contentsToRootView(renderer->absoluteBoundingBoxRect());
2291             frameView->setCustomFixedPositionLayoutRect(currentFixedPositionRect);
2292             
2293             if (!information.elementRect.contains(information.selectionRect))
2294                 information.selectionRect.setLocation(information.elementRect.location());
2295         }
2296     } else
2297         information.elementRect = IntRect();
2298
2299     information.minimumScaleFactor = minimumPageScaleFactor();
2300     information.maximumScaleFactor = maximumPageScaleFactor();
2301     information.allowsUserScaling = m_viewportConfiguration.allowsUserScaling();
2302     information.hasNextNode = hasAssistableElement(m_assistedNode.get(), *m_page, true);
2303     information.hasPreviousNode = hasAssistableElement(m_assistedNode.get(), *m_page, false);
2304
2305     if (is<HTMLSelectElement>(*m_assistedNode)) {
2306         HTMLSelectElement& element = downcast<HTMLSelectElement>(*m_assistedNode);
2307         information.elementType = InputType::Select;
2308         const Vector<HTMLElement*>& items = element.listItems();
2309         size_t count = items.size();
2310         int parentGroupID = 0;
2311         // The parent group ID indicates the group the option belongs to and is 0 for group elements.
2312         // If there are option elements in between groups, they are given it's own group identifier.
2313         // If a select does not have groups, all the option elements have group ID 0.
2314         for (size_t i = 0; i < count; ++i) {
2315             HTMLElement* item = items[i];
2316             if (is<HTMLOptionElement>(*item)) {
2317                 HTMLOptionElement& option = downcast<HTMLOptionElement>(*item);
2318                 information.selectOptions.append(OptionItem(option.text(), false, parentGroupID, option.selected(), option.fastHasAttribute(WebCore::HTMLNames::disabledAttr)));
2319             } else if (is<HTMLOptGroupElement>(*item)) {
2320                 HTMLOptGroupElement& group = downcast<HTMLOptGroupElement>(*item);
2321                 parentGroupID++;
2322                 information.selectOptions.append(OptionItem(group.groupLabelText(), true, 0, false, group.fastHasAttribute(WebCore::HTMLNames::disabledAttr)));
2323             }
2324         }
2325         information.selectedIndex = element.selectedIndex();
2326         information.isMultiSelect = element.multiple();
2327     } else if (is<HTMLTextAreaElement>(*m_assistedNode)) {
2328         HTMLTextAreaElement& element = downcast<HTMLTextAreaElement>(*m_assistedNode);
2329         information.autocapitalizeType = static_cast<WebAutocapitalizeType>(element.autocapitalizeType());
2330         information.isAutocorrect = element.autocorrect();
2331         information.elementType = InputType::TextArea;
2332         information.isReadOnly = element.isReadOnly();
2333         information.value = element.value();
2334     } else if (is<HTMLInputElement>(*m_assistedNode)) {
2335         HTMLInputElement& element = downcast<HTMLInputElement>(*m_assistedNode);
2336         HTMLFormElement* form = element.form();
2337         if (form)
2338             information.formAction = form->getURLAttribute(WebCore::HTMLNames::actionAttr);
2339         information.autocapitalizeType = static_cast<WebAutocapitalizeType>(element.autocapitalizeType());
2340         information.isAutocorrect = element.autocorrect();
2341         if (element.isPasswordField())
2342             information.elementType = InputType::Password;
2343         else if (element.isSearchField())
2344             information.elementType = InputType::Search;
2345         else if (element.isEmailField())
2346             information.elementType = InputType::Email;
2347         else if (element.isTelephoneField())
2348             information.elementType = InputType::Phone;
2349         else if (element.isNumberField())
2350             information.elementType = element.getAttribute("pattern") == "\\d*" || element.getAttribute("pattern") == "[0-9]*" ? InputType::NumberPad : InputType::Number;
2351         else if (element.isDateTimeLocalField())
2352             information.elementType = InputType::DateTimeLocal;
2353         else if (element.isDateField())
2354             information.elementType = InputType::Date;
2355         else if (element.isDateTimeField())
2356             information.elementType = InputType::DateTime;
2357         else if (element.isTimeField())
2358             information.elementType = InputType::Time;
2359         else if (element.isWeekField())
2360             information.elementType = InputType::Week;
2361         else if (element.isMonthField())
2362             information.elementType = InputType::Month;
2363         else if (element.isURLField())
2364             information.elementType = InputType::URL;
2365         else if (element.isText()) {
2366             const AtomicString& pattern = element.fastGetAttribute(HTMLNames::patternAttr);
2367             if (pattern == "\\d*" || pattern == "[0-9]*")
2368                 information.elementType = InputType::NumberPad;
2369             else {
2370                 information.elementType = InputType::Text;
2371                 if (!information.formAction.isEmpty()
2372                     && (element.getNameAttribute().contains("search") || element.getIdAttribute().contains("search") || element.fastGetAttribute(HTMLNames::titleAttr).contains("search")))
2373                     information.elementType = InputType::Search;
2374             }
2375         }
2376
2377         information.isReadOnly = element.isReadOnly();
2378         information.value = element.value();
2379         information.valueAsNumber = element.valueAsNumber();
2380         information.title = element.title();
2381     } else if (m_assistedNode->hasEditableStyle()) {
2382         information.elementType = InputType::ContentEditable;
2383         information.isAutocorrect = true;   // FIXME: Should we look at the attribute?
2384         information.autocapitalizeType = WebAutocapitalizeTypeSentences; // FIXME: Should we look at the attribute?
2385         information.isReadOnly = false;
2386     }
2387 }
2388
2389 void WebPage::resetAssistedNodeForFrame(WebFrame* frame)
2390 {
2391     if (!m_assistedNode)
2392         return;
2393     if (m_assistedNode->document().frame() == frame->coreFrame()) {
2394         send(Messages::WebPageProxy::StopAssistingNode());
2395         m_assistedNode = nullptr;
2396     }
2397 }
2398
2399 void WebPage::elementDidFocus(WebCore::Node* node)
2400 {
2401     if (node->hasTagName(WebCore::HTMLNames::selectTag) || node->hasTagName(WebCore::HTMLNames::inputTag) || node->hasTagName(WebCore::HTMLNames::textareaTag) || node->hasEditableStyle()) {
2402         m_assistedNode = node;
2403         AssistedNodeInformation information;
2404         getAssistedNodeInformation(information);
2405         RefPtr<API::Object> userData;
2406
2407         // FIXME: We check m_userIsInteracting so that we don't begin an input session for a
2408         // programmatic focus that doesn't cause the keyboard to appear. But this misses the case of
2409         // a programmatic focus happening while the keyboard is already shown. Once we have a way to
2410         // know the keyboard state in the Web Process, we should refine the condition.
2411         if (m_userIsInteracting)
2412             m_formClient->willBeginInputSession(this, downcast<Element>(node), WebFrame::fromCoreFrame(*node->document().frame()), userData);
2413
2414         send(Messages::WebPageProxy::StartAssistingNode(information, m_userIsInteracting, m_hasPendingBlurNotification, UserData(WebProcess::singleton().transformObjectsToHandles(userData.get()).get())));
2415         m_hasPendingBlurNotification = false;
2416     }
2417 }
2418
2419 void WebPage::elementDidBlur(WebCore::Node* node)
2420 {
2421     if (m_assistedNode == node) {
2422         m_hasPendingBlurNotification = true;
2423         dispatch_async(dispatch_get_main_queue(), ^{
2424             if (m_hasPendingBlurNotification)
2425                 send(Messages::WebPageProxy::StopAssistingNode());
2426             m_hasPendingBlurNotification = false;
2427         });
2428         m_assistedNode = 0;
2429     }
2430 }
2431
2432 void WebPage::setViewportConfigurationMinimumLayoutSize(const FloatSize& size)
2433 {
2434     resetTextAutosizingBeforeLayoutIfNeeded(m_viewportConfiguration.minimumLayoutSize(), size);
2435     m_viewportConfiguration.setMinimumLayoutSize(size);
2436     viewportConfigurationChanged();
2437 }
2438
2439 void WebPage::setMaximumUnobscuredSize(const FloatSize& maximumUnobscuredSize)
2440 {
2441     m_maximumUnobscuredSize = maximumUnobscuredSize;
2442     updateViewportSizeForCSSViewportUnits();
2443 }
2444
2445 void WebPage::setDeviceOrientation(int32_t deviceOrientation)
2446 {
2447     if (deviceOrientation == m_deviceOrientation)
2448         return;
2449     m_deviceOrientation = deviceOrientation;
2450     m_page->mainFrame().orientationChanged();
2451 }
2452
2453 // WebCore stores the page scale factor as float instead of double. When we get a scale from WebCore,
2454 // we need to ignore differences that are within a small rounding error on floats.
2455 static inline bool areEssentiallyEqualAsFloat(float a, float b)
2456 {
2457     return WTF::areEssentiallyEqual(a, b);
2458 }
2459
2460 void WebPage::resetTextAutosizingBeforeLayoutIfNeeded(const FloatSize& oldSize, const FloatSize& newSize)
2461 {
2462     if (oldSize.width() == newSize.width())
2463         return;
2464
2465     for (Frame* frame = &m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
2466         Document* document = frame->document();
2467         if (!document || !document->renderView())
2468             continue;
2469         document->renderView()->resetTextAutosizing();
2470     }
2471 }
2472
2473 void WebPage::dynamicViewportSizeUpdate(const FloatSize& minimumLayoutSize, const WebCore::FloatSize& maximumUnobscuredSize, const FloatRect& targetExposedContentRect, const FloatRect& targetUnobscuredRect, const WebCore::FloatRect& targetUnobscuredRectInScrollViewCoordinates, double targetScale, int32_t deviceOrientation, uint64_t dynamicViewportSizeUpdateID)
2474 {
2475     TemporaryChange<bool> dynamicSizeUpdateGuard(m_inDynamicSizeUpdate, true);
2476     // FIXME: this does not handle the cases where the content would change the content size or scroll position from JavaScript.
2477     // To handle those cases, we would need to redo this computation on every change until the next visible content rect update.
2478
2479     FrameView& frameView = *m_page->mainFrame().view();
2480     IntSize oldContentSize = frameView.contentsSize();
2481     float oldPageScaleFactor = m_page->pageScaleFactor();
2482
2483     m_dynamicSizeUpdateHistory.add(std::make_pair(oldContentSize, oldPageScaleFactor), IntPoint(frameView.scrollOffset()));
2484
2485     RefPtr<Node> oldNodeAtCenter;
2486     double visibleHorizontalFraction = 1;
2487     float relativeHorizontalPositionInNodeAtCenter = 0;
2488     float relativeVerticalPositionInNodeAtCenter = 0;
2489     {
2490         visibleHorizontalFraction = frameView.unobscuredContentSize().width() / oldContentSize.width();
2491         IntPoint unobscuredContentRectCenter = frameView.unobscuredContentRect().center();
2492
2493         HitTestResult hitTestResult = HitTestResult(unobscuredContentRectCenter);
2494
2495         if (RenderView* mainFrameRenderView = frameView.renderView())
2496             mainFrameRenderView->hitTest(HitTestRequest(), hitTestResult);
2497
2498         if (Node* node = hitTestResult.innerNode()) {
2499             if (RenderObject* renderer = node->renderer()) {
2500                 FrameView& containingView = *node->document().frame()->view();
2501                 FloatRect boundingBox = containingView.contentsToRootView(renderer->absoluteBoundingBoxRect(true));
2502                 relativeHorizontalPositionInNodeAtCenter = (unobscuredContentRectCenter.x() - boundingBox.x()) / boundingBox.width();
2503                 relativeVerticalPositionInNodeAtCenter = (unobscuredContentRectCenter.y() - boundingBox.y()) / boundingBox.height();
2504                 oldNodeAtCenter = node;
2505             }
2506         }
2507     }
2508
2509     resetTextAutosizingBeforeLayoutIfNeeded(m_viewportConfiguration.minimumLayoutSize(), minimumLayoutSize);
2510     m_viewportConfiguration.setMinimumLayoutSize(minimumLayoutSize);
2511     IntSize newLayoutSize = m_viewportConfiguration.layoutSize();
2512
2513     setFixedLayoutSize(newLayoutSize);
2514     setMaximumUnobscuredSize(maximumUnobscuredSize);
2515
2516     frameView.updateLayoutAndStyleIfNeededRecursive();
2517
2518     IntSize newContentSize = frameView.contentsSize();
2519
2520     double scale = scaleAfterViewportWidthChange(targetScale, m_userHasChangedPageScaleFactor, m_viewportConfiguration, targetUnobscuredRectInScrollViewCoordinates.width(), newContentSize, oldContentSize, visibleHorizontalFraction);
2521     FloatRect newUnobscuredContentRect = targetUnobscuredRect;
2522     FloatRect newExposedContentRect = targetExposedContentRect;
2523
2524     bool scaleChanged = !areEssentiallyEqualAsFloat(scale, targetScale);
2525     if (scaleChanged) {
2526         // The target scale the UI is using cannot be reached by the content. We need to compute new targets based
2527         // on the viewport constraint and report everything back to the UIProcess.
2528
2529         // 1) Compute a new unobscured rect centered around the original one.
2530         double scaleDifference = targetScale / scale;
2531         double newUnobscuredRectWidth = targetUnobscuredRect.width() * scaleDifference;
2532         double newUnobscuredRectHeight = targetUnobscuredRect.height() * scaleDifference;
2533         double newUnobscuredRectX = targetUnobscuredRect.x() - (newUnobscuredRectWidth - targetUnobscuredRect.width()) / 2;
2534         double newUnobscuredRectY = targetUnobscuredRect.y() - (newUnobscuredRectHeight - targetUnobscuredRect.height()) / 2;
2535         newUnobscuredContentRect = FloatRect(newUnobscuredRectX, newUnobscuredRectY, newUnobscuredRectWidth, newUnobscuredRectHeight);
2536
2537         // 2) Extend our new unobscuredRect by the obscured margins to get a new exposed rect.
2538         double obscuredTopMargin = (targetUnobscuredRect.y() - targetExposedContentRect.y()) * scaleDifference;
2539         double obscuredLeftMargin = (targetUnobscuredRect.x() - targetExposedContentRect.x()) * scaleDifference;
2540         double obscuredBottomMargin = (targetExposedContentRect.maxY() - targetUnobscuredRect.maxY()) * scaleDifference;
2541         double obscuredRightMargin = (targetExposedContentRect.maxX() - targetUnobscuredRect.maxX()) * scaleDifference;
2542         newExposedContentRect = FloatRect(newUnobscuredRectX - obscuredLeftMargin,
2543                                           newUnobscuredRectY - obscuredTopMargin,
2544                                           newUnobscuredRectWidth + obscuredLeftMargin + obscuredRightMargin,
2545                                           newUnobscuredRectHeight + obscuredTopMargin + obscuredBottomMargin);
2546     }
2547
2548     if (oldContentSize != newContentSize || scaleChanged) {
2549         // Snap the new unobscured rect back into the content rect.
2550         newUnobscuredContentRect.setWidth(std::min(static_cast<float>(newContentSize.width()), newUnobscuredContentRect.width()));
2551         newUnobscuredContentRect.setHeight(std::min(static_cast<float>(newContentSize.height()), newUnobscuredContentRect.height()));
2552
2553         bool positionWasRestoredFromSizeUpdateHistory = false;
2554         const auto& previousPosition = m_dynamicSizeUpdateHistory.find(std::pair<IntSize, float>(newContentSize, scale));
2555         if (previousPosition != m_dynamicSizeUpdateHistory.end()) {
2556             IntPoint restoredPosition = previousPosition->value;
2557             FloatPoint deltaPosition(restoredPosition.x() - newUnobscuredContentRect.x(), restoredPosition.y() - newUnobscuredContentRect.y());
2558             newUnobscuredContentRect.moveBy(deltaPosition);
2559             newExposedContentRect.moveBy(deltaPosition);
2560             positionWasRestoredFromSizeUpdateHistory = true;
2561         } else if (oldContentSize != newContentSize) {
2562             FloatPoint newRelativeContentCenter;
2563
2564             if (RenderObject* renderer = oldNodeAtCenter ? oldNodeAtCenter->renderer() : nullptr) {
2565                 FrameView& containingView = *oldNodeAtCenter->document().frame()->view();
2566                 FloatRect newBoundingBox = containingView.contentsToRootView(renderer->absoluteBoundingBoxRect(true));
2567                 newRelativeContentCenter = FloatPoint(newBoundingBox.x() + relativeHorizontalPositionInNodeAtCenter * newBoundingBox.width(), newBoundingBox.y() + relativeVerticalPositionInNodeAtCenter * newBoundingBox.height());
2568             } else
2569                 newRelativeContentCenter = relativeCenterAfterContentSizeChange(targetUnobscuredRect, oldContentSize, newContentSize);
2570
2571             FloatPoint newUnobscuredContentRectCenter = newUnobscuredContentRect.center();
2572             FloatPoint positionDelta(newRelativeContentCenter.x() - newUnobscuredContentRectCenter.x(), newRelativeContentCenter.y() - newUnobscuredContentRectCenter.y());
2573             newUnobscuredContentRect.moveBy(positionDelta);
2574             newExposedContentRect.moveBy(positionDelta);
2575         }
2576
2577         // Make the top/bottom edges "sticky" within 1 pixel.
2578         if (!positionWasRestoredFromSizeUpdateHistory) {
2579             if (targetUnobscuredRect.maxY() > oldContentSize.height() - 1) {
2580                 float bottomVerticalPosition = newContentSize.height() - newUnobscuredContentRect.height();
2581                 newUnobscuredContentRect.setY(bottomVerticalPosition);
2582                 newExposedContentRect.setY(bottomVerticalPosition);
2583             }
2584             if (targetUnobscuredRect.y() < 1) {
2585                 newUnobscuredContentRect.setY(0);
2586                 newExposedContentRect.setY(0);
2587             }
2588
2589             bool likelyResponsiveDesignViewport = newLayoutSize.width() == minimumLayoutSize.width() && areEssentiallyEqualAsFloat(scale, 1);
2590             bool contentBleedsOutsideLayoutWidth = newContentSize.width() > newLayoutSize.width();
2591             bool originalScrollPositionWasOnTheLeftEdge = targetUnobscuredRect.x() <= 0;
2592             if (likelyResponsiveDesignViewport && contentBleedsOutsideLayoutWidth && originalScrollPositionWasOnTheLeftEdge) {
2593                 // This is a special heuristics for "responsive" design with odd layout. It is quite common for responsive design
2594                 // to have content "bleeding" outside of the minimal layout width, usually from an image or table larger than expected.
2595                 // In those cases, the design usually does not adapt to the new width and remain at the newLayoutSize except for the
2596                 // large boxes.
2597                 // It is worth revisiting this special case as web developers get better with responsive design.
2598                 newExposedContentRect.setX(0);
2599                 newUnobscuredContentRect.setX(0);
2600             }
2601         }
2602
2603         float horizontalAdjustment = 0;
2604         if (newUnobscuredContentRect.maxX() > newContentSize.width())
2605             horizontalAdjustment -= newUnobscuredContentRect.maxX() - newContentSize.width();
2606         float verticalAdjustment = 0;
2607         if (newUnobscuredContentRect.maxY() > newContentSize.height())
2608             verticalAdjustment -= newUnobscuredContentRect.maxY() - newContentSize.height();
2609         if (newUnobscuredContentRect.x() < 0)
2610             horizontalAdjustment += - newUnobscuredContentRect.x();
2611         if (newUnobscuredContentRect.y() < 0)
2612             verticalAdjustment += - newUnobscuredContentRect.y();
2613
2614         FloatPoint adjustmentDelta(horizontalAdjustment, verticalAdjustment);
2615         newUnobscuredContentRect.moveBy(adjustmentDelta);
2616         newExposedContentRect.moveBy(adjustmentDelta);
2617     }
2618
2619     frameView.setScrollVelocity(0, 0, 0, monotonicallyIncreasingTime());
2620
2621     IntPoint roundedUnobscuredContentRectPosition = roundedIntPoint(newUnobscuredContentRect.location());
2622     frameView.setUnobscuredContentSize(newUnobscuredContentRect.size());
2623     m_drawingArea->setExposedContentRect(newExposedContentRect);
2624
2625     scalePage(scale, roundedUnobscuredContentRectPosition);
2626
2627     frameView.updateLayoutAndStyleIfNeededRecursive();
2628     IntRect fixedPositionLayoutRect = enclosingIntRect(frameView.viewportConstrainedObjectsRect());
2629     frameView.setCustomFixedPositionLayoutRect(fixedPositionLayoutRect);
2630
2631     frameView.setCustomSizeForResizeEvent(expandedIntSize(targetUnobscuredRectInScrollViewCoordinates.size()));
2632     setDeviceOrientation(deviceOrientation);
2633     frameView.setScrollOffset(roundedUnobscuredContentRectPosition);
2634
2635     m_drawingArea->scheduleCompositingLayerFlush();
2636
2637     send(Messages::WebPageProxy::DynamicViewportUpdateChangedTarget(pageScaleFactor(), frameView.scrollPosition(), dynamicViewportSizeUpdateID));
2638 }
2639
2640 void WebPage::synchronizeDynamicViewportUpdate(double& newTargetScale, FloatPoint& newScrollPosition, uint64_t& nextValidLayerTreeTransactionID)
2641 {
2642     newTargetScale = pageScaleFactor();
2643     newScrollPosition = m_page->mainFrame().view()->scrollPosition();
2644     nextValidLayerTreeTransactionID = downcast<RemoteLayerTreeDrawingArea>(*m_drawingArea).nextTransactionID();
2645 }
2646
2647 void WebPage::resetViewportDefaultConfiguration(WebFrame* frame)
2648 {
2649     if (m_useTestingViewportConfiguration) {
2650         m_viewportConfiguration.setDefaultConfiguration(ViewportConfiguration::testingParameters());
2651         return;
2652     }
2653
2654     if (!frame) {
2655         m_viewportConfiguration.setDefaultConfiguration(ViewportConfiguration::webpageParameters());
2656         return;
2657     }
2658
2659     Document* document = frame->coreFrame()->document();
2660     if (document->isImageDocument())
2661         m_viewportConfiguration.setDefaultConfiguration(ViewportConfiguration::imageDocumentParameters());
2662     else if (document->isTextDocument())
2663         m_viewportConfiguration.setDefaultConfiguration(ViewportConfiguration::textDocumentParameters());
2664     else
2665         m_viewportConfiguration.setDefaultConfiguration(ViewportConfiguration::webpageParameters());
2666 }
2667
2668 void WebPage::viewportConfigurationChanged()
2669 {
2670     setFixedLayoutSize(m_viewportConfiguration.layoutSize());
2671
2672     double initialScale = m_viewportConfiguration.initialScale();
2673     double scale;
2674     if (m_userHasChangedPageScaleFactor)
2675         scale = std::max(std::min(pageScaleFactor(), m_viewportConfiguration.maximumScale()), m_viewportConfiguration.minimumScale());
2676     else
2677         scale = initialScale;
2678
2679     m_page->setZoomedOutPageScaleFactor(m_viewportConfiguration.minimumScale());
2680
2681     updateViewportSizeForCSSViewportUnits();
2682
2683     FrameView& frameView = *mainFrameView();
2684     IntPoint scrollPosition = frameView.scrollPosition();
2685     if (!m_hasReceivedVisibleContentRectsAfterDidCommitLoad) {
2686         FloatSize minimumLayoutSizeInScrollViewCoordinates = m_viewportConfiguration.minimumLayoutSize();
2687         minimumLayoutSizeInScrollViewCoordinates.scale(1 / scale);
2688         IntSize minimumLayoutSizeInDocumentCoordinates = roundedIntSize(minimumLayoutSizeInScrollViewCoordinates);
2689         frameView.setUnobscuredContentSize(minimumLayoutSizeInDocumentCoordinates);
2690         frameView.setScrollVelocity(0, 0, 0, monotonicallyIncreasingTime());
2691
2692         // FIXME: We could send down the obscured margins to find a better exposed rect and unobscured rect.
2693         // It is not a big deal at the moment because the tile coverage will always extend past the obscured bottom inset.
2694         m_drawingArea->setExposedContentRect(FloatRect(scrollPosition, minimumLayoutSizeInDocumentCoordinates));
2695     }
2696     scalePage(scale, scrollPosition);
2697     
2698     if (!m_hasReceivedVisibleContentRectsAfterDidCommitLoad) {
2699         // This takes scale into account, so do after the scale change.
2700         frameView.setCustomFixedPositionLayoutRect(enclosingIntRect(frameView.viewportConstrainedObjectsRect()));
2701
2702         frameView.setCustomSizeForResizeEvent(expandedIntSize(m_viewportConfiguration.minimumLayoutSize()));
2703     }
2704 }
2705
2706 void WebPage::updateViewportSizeForCSSViewportUnits()
2707 {
2708     FloatSize largestUnobscuredRect = m_maximumUnobscuredSize;
2709     if (largestUnobscuredRect.isEmpty())
2710         largestUnobscuredRect = m_viewportConfiguration.minimumLayoutSize();
2711
2712     FrameView& frameView = *mainFrameView();
2713     largestUnobscuredRect.scale(1 / m_viewportConfiguration.initialScale());
2714     frameView.setViewportSizeForCSSViewportUnits(roundedIntSize(largestUnobscuredRect));
2715 }
2716
2717 void WebPage::applicationWillResignActive()
2718 {
2719     [[NSNotificationCenter defaultCenter] postNotificationName:WebUIApplicationWillResignActiveNotification object:nil];
2720 }
2721
2722 void WebPage::applicationWillEnterForeground()
2723 {
2724     WebProcess::singleton().supplement<WebDatabaseManager>()->setPauseAllDatabases(false);
2725     [[NSNotificationCenter defaultCenter] postNotificationName:WebUIApplicationWillEnterForegroundNotification object:nil];
2726 }
2727
2728 void WebPage::applicationDidEnterBackground(uint64_t callbackID)
2729 {
2730     WebProcess::singleton().supplement<WebDatabaseManager>()->setPauseAllDatabases(true);
2731     send(Messages::WebPageProxy::VoidCallback(callbackID));
2732 }
2733
2734 void WebPage::applicationDidBecomeActive()
2735 {
2736     [[NSNotificationCenter defaultCenter] postNotificationName:WebUIApplicationDidBecomeActiveNotification object:nil];
2737 }
2738
2739 static inline void adjustVelocityDataForBoundedScale(double& horizontalVelocity, double& verticalVelocity, double& scaleChangeRate, double exposedRectScale, double boundedScale)
2740 {
2741     if (scaleChangeRate) {
2742         horizontalVelocity = 0;
2743         verticalVelocity = 0;
2744     }
2745
2746     if (exposedRectScale != boundedScale)
2747         scaleChangeRate = 0;
2748 }
2749
2750 static inline FloatRect adjustExposedRectForBoundedScale(const FloatRect& exposedRect, double exposedRectScale, double newScale)
2751 {
2752     if (exposedRectScale < newScale)
2753         return exposedRect;
2754
2755     return adjustExposedRectForNewScale(exposedRect, exposedRectScale, newScale);
2756 }
2757
2758 void WebPage::updateVisibleContentRects(const VisibleContentRectUpdateInfo& visibleContentRectUpdateInfo, double oldestTimestamp)
2759 {
2760     // Skip any VisibleContentRectUpdate that have been queued before DidCommitLoad suppresses the updates in the UIProcess.
2761     if (visibleContentRectUpdateInfo.lastLayerTreeTransactionID() < m_firstLayerTreeTransactionIDAfterDidCommitLoad)
2762         return;
2763
2764     m_hasReceivedVisibleContentRectsAfterDidCommitLoad = true;
2765     m_isInStableState = visibleContentRectUpdateInfo.inStableState();
2766
2767     double scaleNoiseThreshold = 0.005;
2768     double filteredScale = visibleContentRectUpdateInfo.scale();
2769     double currentScale = m_page->pageScaleFactor();
2770     if (!m_isInStableState && fabs(filteredScale - m_page->pageScaleFactor()) < scaleNoiseThreshold) {
2771         // Tiny changes of scale during interactive zoom cause content to jump by one pixel, creating
2772         // visual noise. We filter those useless updates.
2773         filteredScale = currentScale;
2774     }
2775
2776     double boundedScale = std::min(m_viewportConfiguration.maximumScale(), std::max(m_viewportConfiguration.minimumScale(), filteredScale));
2777
2778     // Skip progressively redrawing tiles if pinch-zooming while the system is under memory pressure.
2779     if (boundedScale != currentScale && !m_isInStableState && MemoryPressureHandler::singleton().isUnderMemoryPressure())
2780         return;
2781
2782     if (m_isInStableState)
2783         m_hasStablePageScaleFactor = true;
2784     else {
2785         if (m_oldestNonStableUpdateVisibleContentRectsTimestamp == std::chrono::milliseconds::zero())
2786             m_oldestNonStableUpdateVisibleContentRectsTimestamp = std::chrono::milliseconds(static_cast<std::chrono::milliseconds::rep>(oldestTimestamp * 1000));
2787     }
2788
2789     FloatRect exposedRect = visibleContentRectUpdateInfo.exposedRect();
2790     FloatRect adjustedExposedRect = adjustExposedRectForBoundedScale(exposedRect, visibleContentRectUpdateInfo.scale(), boundedScale);
2791     m_drawingArea->setExposedContentRect(adjustedExposedRect);
2792
2793     IntPoint scrollPosition = roundedIntPoint(visibleContentRectUpdateInfo.unobscuredRect().location());
2794
2795     float floatBoundedScale = boundedScale;
2796     bool hasSetPageScale = false;
2797     if (floatBoundedScale != currentScale) {
2798         m_scaleWasSetByUIProcess = true;
2799         m_hasStablePageScaleFactor = m_isInStableState;
2800
2801         m_dynamicSizeUpdateHistory.clear();
2802
2803         m_page->setPageScaleFactor(floatBoundedScale, scrollPosition, m_isInStableState);
2804         hasSetPageScale = true;
2805
2806         if (LayerTreeHost* layerTreeHost = m_drawingArea->layerTreeHost())
2807             layerTreeHost->deviceOrPageScaleFactorChanged();
2808         send(Messages::WebPageProxy::PageScaleFactorDidChange(floatBoundedScale));
2809     }
2810
2811     if (!hasSetPageScale && m_isInStableState) {
2812         m_page->setPageScaleFactor(floatBoundedScale, scrollPosition, true);
2813         hasSetPageScale = true;
2814     }
2815
2816     FrameView& frameView = *m_page->mainFrame().view();
2817     if (scrollPosition != frameView.scrollPosition())
2818         m_dynamicSizeUpdateHistory.clear();
2819
2820     frameView.setUnobscuredContentSize(visibleContentRectUpdateInfo.unobscuredRect().size());
2821
2822     double horizontalVelocity = visibleContentRectUpdateInfo.horizontalVelocity();
2823     double verticalVelocity = visibleContentRectUpdateInfo.verticalVelocity();
2824     double scaleChangeRate = visibleContentRectUpdateInfo.scaleChangeRate();
2825     adjustVelocityDataForBoundedScale(horizontalVelocity, verticalVelocity, scaleChangeRate, visibleContentRectUpdateInfo.scale(), boundedScale);
2826
2827     frameView.setScrollVelocity(horizontalVelocity, verticalVelocity, scaleChangeRate, visibleContentRectUpdateInfo.timestamp());
2828
2829     if (m_isInStableState)
2830         frameView.setCustomFixedPositionLayoutRect(enclosingIntRect(visibleContentRectUpdateInfo.customFixedPositionRect()));
2831
2832     if (!visibleContentRectUpdateInfo.isChangingObscuredInsetsInteractively())
2833         frameView.setCustomSizeForResizeEvent(expandedIntSize(visibleContentRectUpdateInfo.unobscuredRectInScrollViewCoordinates().size()));
2834
2835     frameView.setConstrainsScrollingToContentEdge(false);
2836     frameView.setScrollOffset(scrollPosition);
2837     frameView.setConstrainsScrollingToContentEdge(true);
2838 }
2839
2840 void WebPage::willStartUserTriggeredZooming()
2841 {
2842     m_page->mainFrame().diagnosticLoggingClient().logDiagnosticMessageWithValue(DiagnosticLoggingKeys::webViewKey(), DiagnosticLoggingKeys::userKey(), DiagnosticLoggingKeys::zoomedKey(), ShouldSample::No);
2843     m_userHasChangedPageScaleFactor = true;
2844 }
2845
2846 #if ENABLE(WEBGL)
2847 WebCore::WebGLLoadPolicy WebPage::webGLPolicyForURL(WebFrame*, const String&)
2848 {
2849     return WKShouldBlockWebGL() ? WebGLBlockCreation : WebGLAllowCreation;
2850 }
2851
2852 WebCore::WebGLLoadPolicy WebPage::resolveWebGLPolicyForURL(WebFrame*, const String&)
2853 {
2854     return WKShouldBlockWebGL() ? WebGLBlockCreation : WebGLAllowCreation;
2855 }
2856 #endif
2857
2858 void WebPage::zoomToRect(FloatRect rect, double minimumScale, double maximumScale)
2859 {
2860     send(Messages::WebPageProxy::ZoomToRect(rect, minimumScale, maximumScale));
2861 }
2862
2863 #if ENABLE(IOS_TOUCH_EVENTS)
2864 void WebPage::dispatchAsynchronousTouchEvents(const Vector<WebTouchEvent, 1>& queue)
2865 {
2866     bool ignored;
2867     for (const WebTouchEvent& event : queue)
2868         dispatchTouchEvent(event, ignored);
2869 }
2870 #endif
2871
2872 void WebPage::computePagesForPrintingAndStartDrawingToPDF(uint64_t frameID, const PrintInfo& printInfo, uint32_t firstPage, PassRefPtr<Messages::WebPage::ComputePagesForPrintingAndStartDrawingToPDF::DelayedReply> reply)
2873 {
2874     Vector<WebCore::IntRect> pageRects;
2875     double totalScaleFactor = 1;
2876     computePagesForPrintingImpl(frameID, printInfo, pageRects, totalScaleFactor);
2877     std::size_t pageCount = pageRects.size();
2878     reply->send(WTF::move(pageRects), totalScaleFactor);
2879
2880     RetainPtr<CFMutableDataRef> pdfPageData;
2881     drawPagesToPDFImpl(frameID, printInfo, firstPage, pageCount - firstPage, pdfPageData);
2882     send(Messages::WebPageProxy::DidFinishDrawingPagesToPDF(IPC::DataReference(CFDataGetBytePtr(pdfPageData.get()), CFDataGetLength(pdfPageData.get()))));
2883 }
2884
2885 void WebPage::contentSizeCategoryDidChange(const String& contentSizeCategory)
2886 {
2887     RenderThemeIOS::setContentSizeCategory(contentSizeCategory);
2888     Page::updateStyleForAllPagesAfterGlobalChangeInEnvironment();
2889 }
2890
2891 String WebPage::platformUserAgent(const URL&) const
2892 {
2893     return String();
2894 }
2895
2896 } // namespace WebKit
2897
2898 #endif // PLATFORM(IOS)