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