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