69a51d20167534fa849a7c7b3878d3312ac13a0b
[WebKit-https.git] / Source / WebKit2 / UIProcess / ios / WebPageProxyIOS.mm
1 /*
2  * Copyright (C) 2012-2016 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 "WebPageProxy.h"
28
29 #if PLATFORM(IOS)
30
31 #import "APIUIClient.h"
32 #import "DataReference.h"
33 #import "EditingRange.h"
34 #import "InteractionInformationAtPosition.h"
35 #import "Logging.h"
36 #import "NativeWebKeyboardEvent.h"
37 #import "PageClient.h"
38 #import "PrintInfo.h"
39 #import "RemoteLayerTreeDrawingAreaProxy.h"
40 #import "RemoteLayerTreeDrawingAreaProxyMessages.h"
41 #import "RemoteLayerTreeTransaction.h"
42 #import "UIKitSPI.h"
43 #import "UserData.h"
44 #import "ViewUpdateDispatcherMessages.h"
45 #import "WKBrowsingContextControllerInternal.h"
46 #import "WebPageMessages.h"
47 #import "WebProcessProxy.h"
48 #import "WebVideoFullscreenManagerProxy.h"
49 #import <WebCore/FrameView.h>
50 #import <WebCore/NotImplemented.h>
51 #import <WebCore/PlatformScreen.h>
52 #import <WebCore/SharedBuffer.h>
53 #import <WebCore/TextStream.h>
54 #import <WebCore/UserAgent.h>
55 #import <WebCore/ValidationBubble.h>
56
57 #if USE(QUICK_LOOK)
58 #import "APILoaderClient.h"
59 #import "APINavigationClient.h"
60 #import <wtf/text/WTFString.h>
61 #endif
62
63 using namespace WebCore;
64
65 namespace WebKit {
66
67 void WebPageProxy::platformInitialize()
68 {
69 }
70
71 static String webKitBundleVersionString()
72 {
73     return [[NSBundle bundleForClass:NSClassFromString(@"WKWebView")] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey];
74 }
75
76 String WebPageProxy::standardUserAgent(const String& applicationNameForUserAgent)
77 {
78     return standardUserAgentWithApplicationName(applicationNameForUserAgent, webKitBundleVersionString());
79 }
80
81 void WebPageProxy::getIsSpeaking(bool&)
82 {
83     notImplemented();
84 }
85
86 void WebPageProxy::speak(const String&)
87 {
88     notImplemented();
89 }
90
91 void WebPageProxy::stopSpeaking()
92 {
93     notImplemented();
94 }
95
96 void WebPageProxy::searchWithSpotlight(const String&)
97 {
98     notImplemented();
99 }
100
101 void WebPageProxy::searchTheWeb(const String&)
102 {
103     notImplemented();
104 }
105
106 void WebPageProxy::windowAndViewFramesChanged(const FloatRect&, const FloatPoint&)
107 {
108     notImplemented();
109 }
110
111 String WebPageProxy::stringSelectionForPasteboard()
112 {
113     notImplemented();
114     return String();
115 }
116
117 RefPtr<WebCore::SharedBuffer> WebPageProxy::dataSelectionForPasteboard(const String&)
118 {
119     notImplemented();
120     return nullptr;
121 }
122
123 bool WebPageProxy::readSelectionFromPasteboard(const String&)
124 {
125     notImplemented();
126     return false;
127 }
128
129 void WebPageProxy::performDictionaryLookupAtLocation(const WebCore::FloatPoint&)
130 {
131     notImplemented();
132 }
133
134 void WebPageProxy::gestureCallback(const WebCore::IntPoint& point, uint32_t gestureType, uint32_t gestureState, uint32_t flags, uint64_t callbackID)
135 {
136     auto callback = m_callbacks.take<GestureCallback>(callbackID);
137     if (!callback) {
138         ASSERT_NOT_REACHED();
139         return;
140     }
141     
142     callback->performCallbackWithReturnValue(point, gestureType, gestureState, flags);
143 }
144
145 void WebPageProxy::touchesCallback(const WebCore::IntPoint& point, uint32_t touches, uint32_t flags, uint64_t callbackID)
146 {
147     auto callback = m_callbacks.take<TouchesCallback>(callbackID);
148     if (!callback) {
149         ASSERT_NOT_REACHED();
150         return;
151     }
152
153     callback->performCallbackWithReturnValue(point, touches, flags);
154 }
155
156 void WebPageProxy::autocorrectionDataCallback(const Vector<WebCore::FloatRect>& rects, const String& fontName, float fontSize, uint64_t fontTraits, uint64_t callbackID)
157 {
158     auto callback = m_callbacks.take<AutocorrectionDataCallback>(callbackID);
159     if (!callback) {
160         ASSERT_NOT_REACHED();
161         return;
162     }
163
164     callback->performCallbackWithReturnValue(rects, fontName, fontSize, fontTraits);
165 }
166
167 void WebPageProxy::selectionContextCallback(const String& selectedText, const String& beforeText, const String& afterText, uint64_t callbackID)
168 {
169     auto callback = m_callbacks.take<SelectionContextCallback>(callbackID);
170     if (!callback) {
171         ASSERT_NOT_REACHED();
172         return;
173     }
174
175     callback->performCallbackWithReturnValue(selectedText, beforeText, afterText);
176 }
177
178 void WebPageProxy::autocorrectionContextCallback(const String& beforeText, const String& markedText, const String& selectedText, const String& afterText, uint64_t location, uint64_t length, uint64_t callbackID)
179 {
180     auto callback = m_callbacks.take<AutocorrectionContextCallback>(callbackID);
181     if (!callback) {
182         ASSERT_NOT_REACHED();
183         return;
184     }
185
186     callback->performCallbackWithReturnValue(beforeText, markedText, selectedText, afterText, location, length);
187 }
188
189 void WebPageProxy::updateVisibleContentRects(const VisibleContentRectUpdateInfo& visibleContentRectUpdate)
190 {
191     if (!isValid())
192         return;
193
194     if (visibleContentRectUpdate == m_lastVisibleContentRectUpdate)
195         return;
196
197     m_lastVisibleContentRectUpdate = visibleContentRectUpdate;
198     m_process->send(Messages::ViewUpdateDispatcher::VisibleContentRectUpdate(m_pageID, visibleContentRectUpdate), 0);
199 }
200
201 void WebPageProxy::resendLastVisibleContentRects()
202 {
203     m_process->send(Messages::ViewUpdateDispatcher::VisibleContentRectUpdate(m_pageID, m_lastVisibleContentRectUpdate), 0);
204 }
205
206 static inline float adjustedUnexposedEdge(float documentEdge, float exposedRectEdge, float factor)
207 {
208     if (exposedRectEdge < documentEdge)
209         return documentEdge - factor * (documentEdge - exposedRectEdge);
210     
211     return exposedRectEdge;
212 }
213
214 static inline float adjustedUnexposedMaxEdge(float documentEdge, float exposedRectEdge, float factor)
215 {
216     if (exposedRectEdge > documentEdge)
217         return documentEdge + factor * (exposedRectEdge - documentEdge);
218     
219     return exposedRectEdge;
220 }
221
222 // FIXME: rename this when visual viewports are the default.
223 WebCore::FloatRect WebPageProxy::computeCustomFixedPositionRect(const FloatRect& unobscuredContentRect, const FloatRect& currentCustomFixedPositionRect, double displayedContentScale, UnobscuredRectConstraint constraint, bool visualViewportEnabled) const
224 {
225     FloatRect constrainedUnobscuredRect = unobscuredContentRect;
226     FloatRect documentRect = m_pageClient.documentRect();
227
228     if (m_pageClient.isAssistingNode())
229         return documentRect;
230
231     if (constraint == UnobscuredRectConstraint::ConstrainedToDocumentRect)
232         constrainedUnobscuredRect.intersect(documentRect);
233
234     double minimumScale = m_pageClient.minimumZoomScale();
235     
236     if (displayedContentScale < minimumScale) {
237         const CGFloat slope = 12;
238         CGFloat factor = std::max<CGFloat>(1 - slope * (minimumScale - displayedContentScale), 0);
239             
240         constrainedUnobscuredRect.setX(adjustedUnexposedEdge(documentRect.x(), constrainedUnobscuredRect.x(), factor));
241         constrainedUnobscuredRect.setY(adjustedUnexposedEdge(documentRect.y(), constrainedUnobscuredRect.y(), factor));
242         constrainedUnobscuredRect.setWidth(adjustedUnexposedMaxEdge(documentRect.maxX(), constrainedUnobscuredRect.maxX(), factor) - constrainedUnobscuredRect.x());
243         constrainedUnobscuredRect.setHeight(adjustedUnexposedMaxEdge(documentRect.maxY(), constrainedUnobscuredRect.maxY(), factor) - constrainedUnobscuredRect.y());
244     }
245     
246     if (visualViewportEnabled) {
247         FloatRect layoutViewportRect = currentCustomFixedPositionRect;
248         
249         // The layout viewport is never smaller than m_baseLayoutViewportSize, and never be smaller than the constrainedUnobscuredRect.
250         FloatSize constrainedSize = m_baseLayoutViewportSize;
251         layoutViewportRect.setSize(constrainedSize.expandedTo(constrainedUnobscuredRect.size()));
252
253         LayoutPoint layoutViewportOrigin = FrameView::computeLayoutViewportOrigin(enclosingLayoutRect(constrainedUnobscuredRect), m_minStableLayoutViewportOrigin, m_maxStableLayoutViewportOrigin, enclosingLayoutRect(layoutViewportRect));
254         layoutViewportRect.setLocation(layoutViewportOrigin);
255
256         if (layoutViewportRect != currentCustomFixedPositionRect)
257             LOG_WITH_STREAM(VisibleRects, stream << "WebPageProxy::computeCustomFixedPositionRect: new layout viewport  " << layoutViewportRect);
258         return layoutViewportRect;
259     }
260     
261     return FrameView::rectForViewportConstrainedObjects(enclosingLayoutRect(constrainedUnobscuredRect), LayoutSize(documentRect.size()), displayedContentScale, false, StickToViewportBounds);
262 }
263
264 void WebPageProxy::overflowScrollViewWillStartPanGesture()
265 {
266     m_pageClient.overflowScrollViewWillStartPanGesture();
267 }
268
269 void WebPageProxy::overflowScrollViewDidScroll()
270 {
271     m_pageClient.overflowScrollViewDidScroll();
272 }
273
274 void WebPageProxy::overflowScrollWillStartScroll()
275 {
276     m_pageClient.overflowScrollWillStartScroll();
277 }
278
279 void WebPageProxy::overflowScrollDidEndScroll()
280 {
281     m_pageClient.overflowScrollDidEndScroll();
282 }
283
284 void WebPageProxy::dynamicViewportSizeUpdate(const FloatSize& minimumLayoutSize, const WebCore::FloatSize& maximumUnobscuredSize, const FloatRect& targetExposedContentRect, const FloatRect& targetUnobscuredRect, const FloatRect& targetUnobscuredRectInScrollViewCoordinates,  double targetScale, int32_t deviceOrientation)
285 {
286     if (!isValid())
287         return;
288
289     hideValidationMessage();
290
291     m_dynamicViewportSizeUpdateWaitingForTarget = true;
292     m_dynamicViewportSizeUpdateWaitingForLayerTreeCommit = true;
293     m_process->send(Messages::WebPage::DynamicViewportSizeUpdate(minimumLayoutSize, maximumUnobscuredSize, targetExposedContentRect, targetUnobscuredRect, targetUnobscuredRectInScrollViewCoordinates, targetScale, deviceOrientation, ++m_currentDynamicViewportSizeUpdateID), m_pageID);
294 }
295
296 void WebPageProxy::synchronizeDynamicViewportUpdate()
297 {
298     if (!isValid())
299         return;
300
301     if (m_dynamicViewportSizeUpdateWaitingForTarget) {
302         // We do not want the UIProcess to finish animated resize with the old content size, scale, etc.
303         // If that happens, the UIProcess would start pushing new VisibleContentRectUpdateInfo to the WebProcess with
304         // invalid informations.
305         //
306         // Ideally, the animated resize should just be transactional, and the UIProcess would remain in the "resize" state
307         // until both DynamicViewportUpdateChangedTarget and the associated commitLayerTree are finished.
308         // The tricky part with such implementation is if a second animated resize starts before the end of the previous one.
309         // In that case, the values used for the target state needs to be computed from the output of the previous animated resize.
310         //
311         // The following is a workaround to have the UIProcess in a consistent state.
312         // Instead of handling nested resize, we block the UIProcess until the animated resize finishes.
313         double newScale;
314         FloatPoint newScrollPosition;
315         uint64_t nextValidLayerTreeTransactionID;
316         if (m_process->sendSync(Messages::WebPage::SynchronizeDynamicViewportUpdate(), Messages::WebPage::SynchronizeDynamicViewportUpdate::Reply(newScale, newScrollPosition, nextValidLayerTreeTransactionID), m_pageID, 2_s)) {
317             m_dynamicViewportSizeUpdateWaitingForTarget = false;
318             m_dynamicViewportSizeUpdateLayerTreeTransactionID = nextValidLayerTreeTransactionID;
319             m_pageClient.dynamicViewportUpdateChangedTarget(newScale, newScrollPosition, nextValidLayerTreeTransactionID);
320         }
321
322     }
323
324     // If m_dynamicViewportSizeUpdateWaitingForTarget is false, we are waiting for the next valid frame with the hope it is the one for the new target.
325     // If m_dynamicViewportSizeUpdateWaitingForTarget is still true, this is a desperate attempt to get the valid frame before finishing the animation.
326     if (m_dynamicViewportSizeUpdateWaitingForLayerTreeCommit)
327         m_drawingArea->waitForDidUpdateActivityState();
328
329     m_dynamicViewportSizeUpdateWaitingForTarget = false;
330     m_dynamicViewportSizeUpdateWaitingForLayerTreeCommit = false;
331 }
332
333 void WebPageProxy::setViewportConfigurationMinimumLayoutSize(const WebCore::FloatSize& size)
334 {
335     m_process->send(Messages::WebPage::SetViewportConfigurationMinimumLayoutSize(size), m_pageID);
336 }
337
338 void WebPageProxy::setForceAlwaysUserScalable(bool userScalable)
339 {
340     if (m_forceAlwaysUserScalable == userScalable)
341         return;
342     m_forceAlwaysUserScalable = userScalable;
343     m_process->send(Messages::WebPage::SetForceAlwaysUserScalable(userScalable), m_pageID);
344 }
345
346 void WebPageProxy::setMaximumUnobscuredSize(const WebCore::FloatSize& size)
347 {
348     m_process->send(Messages::WebPage::SetMaximumUnobscuredSize(size), m_pageID);
349 }
350
351 void WebPageProxy::setDeviceOrientation(int32_t deviceOrientation)
352 {
353     if (deviceOrientation != m_deviceOrientation) {
354         m_deviceOrientation = deviceOrientation;
355         if (isValid())
356             m_process->send(Messages::WebPage::SetDeviceOrientation(deviceOrientation), m_pageID);
357     }
358 }
359
360 static bool exceedsRenderTreeSizeSizeThreshold(uint64_t thresholdSize, uint64_t committedSize)
361 {
362     const double thesholdSizeFraction = 0.5; // Empirically-derived.
363     return committedSize > thresholdSize * thesholdSizeFraction;
364 }
365
366 void WebPageProxy::didCommitLayerTree(const WebKit::RemoteLayerTreeTransaction& layerTreeTransaction)
367 {
368     m_pageExtendedBackgroundColor = layerTreeTransaction.pageExtendedBackgroundColor();
369
370     if (!m_hasReceivedLayerTreeTransactionAfterDidCommitLoad) {
371         if (layerTreeTransaction.transactionID() >= m_firstLayerTreeTransactionIdAfterDidCommitLoad) {
372             m_hasReceivedLayerTreeTransactionAfterDidCommitLoad = true;
373             m_lastVisibleContentRectUpdate = VisibleContentRectUpdateInfo();
374         }
375     }
376
377     if (!m_dynamicViewportSizeUpdateWaitingForTarget && m_dynamicViewportSizeUpdateWaitingForLayerTreeCommit) {
378         if (layerTreeTransaction.transactionID() >= m_dynamicViewportSizeUpdateLayerTreeTransactionID)
379             m_dynamicViewportSizeUpdateWaitingForLayerTreeCommit = false;
380     }
381
382     m_pageClient.didCommitLayerTree(layerTreeTransaction);
383
384     // FIXME: Remove this special mechanism and fold it into the transaction's layout milestones.
385     if ((m_observedLayoutMilestones & WebCore::ReachedSessionRestorationRenderTreeSizeThreshold) && !m_hitRenderTreeSizeThreshold
386         && exceedsRenderTreeSizeSizeThreshold(m_sessionRestorationRenderTreeSize, layerTreeTransaction.renderTreeSize())) {
387         m_hitRenderTreeSizeThreshold = true;
388         didReachLayoutMilestone(WebCore::ReachedSessionRestorationRenderTreeSizeThreshold);
389     }
390
391     if (m_hasDeferredStartAssistingNode) {
392         m_pageClient.startAssistingNode(m_deferredNodeAssistanceArguments->m_nodeInformation, m_deferredNodeAssistanceArguments->m_userIsInteracting, m_deferredNodeAssistanceArguments->m_blurPreviousNode, m_deferredNodeAssistanceArguments->m_userData.get());
393         m_hasDeferredStartAssistingNode = false;
394         m_deferredNodeAssistanceArguments = nullptr;
395     }
396 }
397
398 bool WebPageProxy::updateLayoutViewportParameters(const WebKit::RemoteLayerTreeTransaction& layerTreeTransaction)
399 {
400     bool changed = m_baseLayoutViewportSize != layerTreeTransaction.baseLayoutViewportSize()
401         || m_minStableLayoutViewportOrigin != layerTreeTransaction.minStableLayoutViewportOrigin()
402         || m_maxStableLayoutViewportOrigin != layerTreeTransaction.maxStableLayoutViewportOrigin();
403
404     m_baseLayoutViewportSize = layerTreeTransaction.baseLayoutViewportSize();
405     m_minStableLayoutViewportOrigin = layerTreeTransaction.minStableLayoutViewportOrigin();
406     m_maxStableLayoutViewportOrigin = layerTreeTransaction.maxStableLayoutViewportOrigin();
407     
408     return changed;
409 }
410
411 void WebPageProxy::layerTreeCommitComplete()
412 {
413     m_pageClient.layerTreeCommitComplete();
414 }
415
416 void WebPageProxy::selectWithGesture(const WebCore::IntPoint point, WebCore::TextGranularity granularity, uint32_t gestureType, uint32_t gestureState, bool isInteractingWithAssistedNode, std::function<void (const WebCore::IntPoint&, uint32_t, uint32_t, uint32_t, CallbackBase::Error)> callbackFunction)
417 {
418     if (!isValid()) {
419         callbackFunction(WebCore::IntPoint(), 0, 0, 0, CallbackBase::Error::Unknown);
420         return;
421     }
422
423     uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
424     m_process->send(Messages::WebPage::SelectWithGesture(point, (uint32_t)granularity, gestureType, gestureState, isInteractingWithAssistedNode, callbackID), m_pageID);
425 }
426
427 void WebPageProxy::updateSelectionWithTouches(const WebCore::IntPoint point, uint32_t touches, bool baseIsStart, std::function<void (const WebCore::IntPoint&, uint32_t, uint32_t, CallbackBase::Error)> callbackFunction)
428 {
429     if (!isValid()) {
430         callbackFunction(WebCore::IntPoint(), 0, 0, CallbackBase::Error::Unknown);
431         return;
432     }
433
434     uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
435     m_process->send(Messages::WebPage::UpdateSelectionWithTouches(point, touches, baseIsStart, callbackID), m_pageID);
436 }
437     
438 void WebPageProxy::replaceDictatedText(const String& oldText, const String& newText)
439 {
440     m_process->send(Messages::WebPage::ReplaceDictatedText(oldText, newText), m_pageID);
441 }
442
443 void WebPageProxy::replaceSelectedText(const String& oldText, const String& newText)
444 {
445     m_process->send(Messages::WebPage::ReplaceSelectedText(oldText, newText), m_pageID);
446 }
447
448 void WebPageProxy::requestAutocorrectionData(const String& textForAutocorrection, std::function<void (const Vector<WebCore::FloatRect>&, const String&, double, uint64_t, CallbackBase::Error)> callbackFunction)
449 {
450     if (!isValid()) {
451         callbackFunction(Vector<WebCore::FloatRect>(), String(), 0, 0, CallbackBase::Error::Unknown);
452         return;
453     }
454
455     uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
456     m_process->send(Messages::WebPage::RequestAutocorrectionData(textForAutocorrection, callbackID), m_pageID);
457 }
458
459 void WebPageProxy::applyAutocorrection(const String& correction, const String& originalText, std::function<void (const String&, CallbackBase::Error)> callbackFunction)
460 {
461     if (!isValid()) {
462         callbackFunction(String(), CallbackBase::Error::Unknown);
463         return;
464     }
465
466     uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
467     m_process->send(Messages::WebPage::ApplyAutocorrection(correction, originalText, callbackID), m_pageID);
468 }
469
470 void WebPageProxy::executeEditCommand(const String& commandName, std::function<void (CallbackBase::Error)> callbackFunction)
471 {
472     if (!isValid()) {
473         callbackFunction(CallbackBase::Error::Unknown);
474         return;
475     }
476     
477     uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
478     m_process->send(Messages::WebPage::ExecuteEditCommandWithCallback(commandName, callbackID), m_pageID);
479 }
480
481 bool WebPageProxy::applyAutocorrection(const String& correction, const String& originalText)
482 {
483     bool autocorrectionApplied = false;
484     m_process->sendSync(Messages::WebPage::SyncApplyAutocorrection(correction, originalText), Messages::WebPage::SyncApplyAutocorrection::Reply(autocorrectionApplied), m_pageID);
485     return autocorrectionApplied;
486 }
487
488 void WebPageProxy::selectTextWithGranularityAtPoint(const WebCore::IntPoint point, WebCore::TextGranularity granularity, bool isInteractingWithAssistedNode, std::function<void (CallbackBase::Error)> callbackFunction)
489 {
490     if (!isValid()) {
491         callbackFunction(CallbackBase::Error::Unknown);
492         return;
493     }
494     
495     uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
496     m_process->send(Messages::WebPage::SelectTextWithGranularityAtPoint(point, static_cast<uint32_t>(granularity), isInteractingWithAssistedNode, callbackID), m_pageID);
497 }
498
499 void WebPageProxy::selectPositionAtBoundaryWithDirection(const WebCore::IntPoint point, WebCore::TextGranularity granularity, WebCore::SelectionDirection direction, bool isInteractingWithAssistedNode, std::function<void (CallbackBase::Error)> callbackFunction)
500 {
501     if (!isValid()) {
502         callbackFunction(CallbackBase::Error::Unknown);
503         return;
504     }
505     
506     uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
507     m_process->send(Messages::WebPage::SelectPositionAtBoundaryWithDirection(point, static_cast<uint32_t>(granularity), static_cast<uint32_t>(direction), isInteractingWithAssistedNode, callbackID), m_pageID);
508 }
509
510 void WebPageProxy::moveSelectionAtBoundaryWithDirection(WebCore::TextGranularity granularity, WebCore::SelectionDirection direction, std::function<void(CallbackBase::Error)> callbackFunction)
511 {
512     if (!isValid()) {
513         callbackFunction(CallbackBase::Error::Unknown);
514         return;
515     }
516     
517     uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
518     m_process->send(Messages::WebPage::MoveSelectionAtBoundaryWithDirection(static_cast<uint32_t>(granularity), static_cast<uint32_t>(direction), callbackID), m_pageID);
519 }
520     
521 void WebPageProxy::selectPositionAtPoint(const WebCore::IntPoint point, bool isInteractingWithAssistedNode, std::function<void (CallbackBase::Error)> callbackFunction)
522 {
523     if (!isValid()) {
524         callbackFunction(CallbackBase::Error::Unknown);
525         return;
526     }
527     
528     uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
529     m_process->send(Messages::WebPage::SelectPositionAtPoint(point, isInteractingWithAssistedNode, callbackID), m_pageID);
530 }
531
532 void WebPageProxy::beginSelectionInDirection(WebCore::SelectionDirection direction, std::function<void (uint64_t, CallbackBase::Error)> callbackFunction)
533 {
534     if (!isValid()) {
535         callbackFunction(0, CallbackBase::Error::Unknown);
536         return;
537     }
538     
539     uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
540     m_process->send(Messages::WebPage::BeginSelectionInDirection(direction, callbackID), m_pageID);
541 }
542
543 void WebPageProxy::updateSelectionWithExtentPoint(const WebCore::IntPoint point, bool isInteractingWithAssistedNode, std::function<void (uint64_t, CallbackBase::Error)> callbackFunction)
544 {
545     if (!isValid()) {
546         callbackFunction(0, CallbackBase::Error::Unknown);
547         return;
548     }
549     
550     uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
551     m_process->send(Messages::WebPage::UpdateSelectionWithExtentPoint(point, isInteractingWithAssistedNode, callbackID), m_pageID);
552     
553 }
554
555 void WebPageProxy::updateSelectionWithExtentPointAndBoundary(const WebCore::IntPoint point, WebCore::TextGranularity granularity, bool isInteractingWithAssistedNode, std::function<void(uint64_t, CallbackBase::Error)> callbackFunction)
556 {
557     if (!isValid()) {
558         callbackFunction(0, CallbackBase::Error::Unknown);
559         return;
560     }
561     
562     uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
563     m_process->send(Messages::WebPage::UpdateSelectionWithExtentPointAndBoundary(point, granularity, isInteractingWithAssistedNode, callbackID), m_pageID);
564     
565 }
566
567 void WebPageProxy::requestDictationContext(std::function<void (const String&, const String&, const String&, CallbackBase::Error)> callbackFunction)
568 {
569     if (!isValid()) {
570         callbackFunction(String(), String(), String(), CallbackBase::Error::Unknown);
571         return;
572     }
573
574     uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
575     m_process->send(Messages::WebPage::RequestDictationContext(callbackID), m_pageID);
576 }
577
578 void WebPageProxy::requestAutocorrectionContext(std::function<void (const String&, const String&, const String&, const String&, uint64_t, uint64_t, CallbackBase::Error)> callbackFunction)
579 {
580     if (!isValid()) {
581         callbackFunction(String(), String(), String(), String(), 0, 0, CallbackBase::Error::Unknown);
582         return;
583     }
584
585     uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
586     m_process->send(Messages::WebPage::RequestAutocorrectionContext(callbackID), m_pageID);
587 }
588
589 void WebPageProxy::getAutocorrectionContext(String& beforeContext, String& markedText, String& selectedText, String& afterContext, uint64_t& location, uint64_t& length)
590 {
591     m_process->sendSync(Messages::WebPage::GetAutocorrectionContext(), Messages::WebPage::GetAutocorrectionContext::Reply(beforeContext, markedText, selectedText, afterContext, location, length), m_pageID);
592 }
593
594 void WebPageProxy::getSelectionContext(std::function<void(const String&, const String&, const String&, CallbackBase::Error)> callbackFunction)
595 {
596     if (!isValid()) {
597         callbackFunction(String(), String(), String(), CallbackBase::Error::Unknown);
598         return;
599     }
600     
601     uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
602     m_process->send(Messages::WebPage::GetSelectionContext(callbackID), m_pageID);
603 }
604
605 void WebPageProxy::handleTwoFingerTapAtPoint(const WebCore::IntPoint& point, uint64_t requestID)
606 {
607     process().send(Messages::WebPage::HandleTwoFingerTapAtPoint(point, requestID), m_pageID);
608 }
609
610 void WebPageProxy::selectWithTwoTouches(const WebCore::IntPoint from, const WebCore::IntPoint to, uint32_t gestureType, uint32_t gestureState, std::function<void (const WebCore::IntPoint&, uint32_t, uint32_t, uint32_t, CallbackBase::Error)> callbackFunction)
611 {
612     if (!isValid()) {
613         callbackFunction(WebCore::IntPoint(), 0, 0, 0, CallbackBase::Error::Unknown);
614         return;
615     }
616
617     uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
618     m_process->send(Messages::WebPage::SelectWithTwoTouches(from, to, gestureType, gestureState, callbackID), m_pageID);
619 }
620
621 void WebPageProxy::updateBlockSelectionWithTouch(const WebCore::IntPoint point, uint32_t touch, uint32_t handlePosition)
622 {
623     m_process->send(Messages::WebPage::UpdateBlockSelectionWithTouch(point, touch, handlePosition), m_pageID);
624 }
625
626 void WebPageProxy::didReceivePositionInformation(const InteractionInformationAtPosition& info)
627 {
628     m_pageClient.positionInformationDidChange(info);
629 }
630
631 void WebPageProxy::getPositionInformation(const InteractionInformationRequest& request, InteractionInformationAtPosition& info)
632 {
633     m_process->sendSync(Messages::WebPage::GetPositionInformation(request), Messages::WebPage::GetPositionInformation::Reply(info), m_pageID);
634 }
635
636 void WebPageProxy::requestPositionInformation(const InteractionInformationRequest& request)
637 {
638     m_process->send(Messages::WebPage::RequestPositionInformation(request), m_pageID);
639 }
640
641 void WebPageProxy::startInteractionWithElementAtPosition(const WebCore::IntPoint& point)
642 {
643     m_process->send(Messages::WebPage::StartInteractionWithElementAtPosition(point), m_pageID);
644 }
645
646 void WebPageProxy::stopInteraction()
647 {
648     m_process->send(Messages::WebPage::StopInteraction(), m_pageID);
649 }
650
651 void WebPageProxy::performActionOnElement(uint32_t action)
652 {
653     m_process->send(Messages::WebPage::PerformActionOnElement(action), m_pageID);
654 }
655
656 void WebPageProxy::saveImageToLibrary(const SharedMemory::Handle& imageHandle, uint64_t imageSize)
657 {
658     RefPtr<SharedMemory> sharedMemoryBuffer = SharedMemory::map(imageHandle, SharedMemory::Protection::ReadOnly);
659     RefPtr<SharedBuffer> buffer = SharedBuffer::create(static_cast<unsigned char*>(sharedMemoryBuffer->data()), imageSize);
660     m_pageClient.saveImageToLibrary(buffer);
661 }
662
663 void WebPageProxy::didUpdateBlockSelectionWithTouch(uint32_t touch, uint32_t flags, float growThreshold, float shrinkThreshold)
664 {
665     m_pageClient.didUpdateBlockSelectionWithTouch(touch, flags, growThreshold, shrinkThreshold);
666 }
667
668 void WebPageProxy::applicationDidEnterBackground()
669 {
670     bool isSuspendedUnderLock = [UIApp isSuspendedUnderLock];
671     m_process->send(Messages::WebPage::ApplicationDidEnterBackground(isSuspendedUnderLock), m_pageID);
672 }
673
674 void WebPageProxy::applicationDidFinishSnapshottingAfterEnteringBackground()
675 {
676     m_drawingArea->prepareForAppSuspension();
677     m_process->send(Messages::WebPage::ApplicationDidFinishSnapshottingAfterEnteringBackground(), m_pageID);
678 }
679
680 void WebPageProxy::applicationWillEnterForeground()
681 {
682     bool isSuspendedUnderLock = [UIApp isSuspendedUnderLock];
683     m_process->send(Messages::WebPage::ApplicationWillEnterForeground(isSuspendedUnderLock), m_pageID);
684 }
685
686 void WebPageProxy::applicationWillResignActive()
687 {
688     m_process->send(Messages::WebPage::ApplicationWillResignActive(), m_pageID);
689 }
690
691 void WebPageProxy::applicationDidBecomeActive()
692 {
693 #if HAVE(AVKIT)
694     if (m_videoFullscreenManager)
695         m_videoFullscreenManager->applicationDidBecomeActive();
696 #endif
697     m_process->send(Messages::WebPage::ApplicationDidBecomeActive(), m_pageID);
698 }
699
700 void WebPageProxy::extendSelection(WebCore::TextGranularity granularity)
701 {
702     m_process->send(Messages::WebPage::ExtendSelection(static_cast<uint32_t>(granularity)), m_pageID);
703 }
704
705 void WebPageProxy::selectWordBackward()
706 {
707     m_process->send(Messages::WebPage::SelectWordBackward(), m_pageID);
708 }
709
710 void WebPageProxy::moveSelectionByOffset(int32_t offset, std::function<void (CallbackBase::Error)> callbackFunction)
711 {
712     if (!isValid()) {
713         callbackFunction(CallbackBase::Error::Unknown);
714         return;
715     }
716     
717     uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
718     m_process->send(Messages::WebPage::MoveSelectionByOffset(offset, callbackID), m_pageID);
719 }
720
721 void WebPageProxy::interpretKeyEvent(const EditorState& state, bool isCharEvent, bool& handled)
722 {
723     m_editorState = state;
724     handled = m_pageClient.interpretKeyEvent(m_keyEventQueue.first(), isCharEvent);
725 }
726
727 // Complex text input support for plug-ins.
728 void WebPageProxy::sendComplexTextInputToPlugin(uint64_t, const String&)
729 {
730     notImplemented();
731 }
732
733 void WebPageProxy::setSmartInsertDeleteEnabled(bool)
734 {
735     notImplemented();
736 }
737
738 void WebPageProxy::registerWebProcessAccessibilityToken(const IPC::DataReference& data)
739 {
740     m_pageClient.accessibilityWebProcessTokenReceived(data);
741 }    
742
743 void WebPageProxy::makeFirstResponder()
744 {
745     notImplemented();
746 }
747
748 void WebPageProxy::registerUIProcessAccessibilityTokens(const IPC::DataReference& elementToken, const IPC::DataReference& windowToken)
749 {
750     if (!isValid())
751         return;
752     
753     process().send(Messages::WebPage::RegisterUIProcessAccessibilityTokens(elementToken, windowToken), m_pageID);
754 }
755
756 void WebPageProxy::pluginFocusOrWindowFocusChanged(uint64_t, bool)
757 {
758     notImplemented();
759 }
760
761 void WebPageProxy::setPluginComplexTextInputState(uint64_t, uint64_t)
762 {
763     notImplemented();
764 }
765
766 void WebPageProxy::executeSavedCommandBySelector(const String&, bool&)
767 {
768     notImplemented();
769 }
770
771 bool WebPageProxy::shouldDelayWindowOrderingForEvent(const WebKit::WebMouseEvent&)
772 {
773     notImplemented();
774     return false;
775 }
776
777 bool WebPageProxy::acceptsFirstMouse(int, const WebKit::WebMouseEvent&)
778 {
779     notImplemented();
780     return false;
781 }
782
783 void WebPageProxy::willStartUserTriggeredZooming()
784 {
785     process().send(Messages::WebPage::WillStartUserTriggeredZooming(), m_pageID);
786 }
787
788 void WebPageProxy::potentialTapAtPosition(const WebCore::FloatPoint& position, uint64_t& requestID)
789 {
790     hideValidationMessage();
791     process().send(Messages::WebPage::PotentialTapAtPosition(requestID, position), m_pageID);
792 }
793
794 void WebPageProxy::commitPotentialTap()
795 {
796     process().send(Messages::WebPage::CommitPotentialTap(m_layerTreeTransactionIdAtLastTouchStart), m_pageID);
797 }
798
799 void WebPageProxy::cancelPotentialTap()
800 {
801     process().send(Messages::WebPage::CancelPotentialTap(), m_pageID);
802 }
803
804 void WebPageProxy::tapHighlightAtPosition(const WebCore::FloatPoint& position, uint64_t& requestID)
805 {
806     process().send(Messages::WebPage::TapHighlightAtPosition(requestID, position), m_pageID);
807 }
808
809 void WebPageProxy::handleTap(const FloatPoint& location)
810 {
811     process().send(Messages::WebPage::HandleTap(roundedIntPoint(location), m_layerTreeTransactionIdAtLastTouchStart), m_pageID);
812 }
813
814 void WebPageProxy::inspectorNodeSearchMovedToPosition(const WebCore::FloatPoint& position)
815 {
816     process().send(Messages::WebPage::InspectorNodeSearchMovedToPosition(position), m_pageID);
817 }
818
819 void WebPageProxy::inspectorNodeSearchEndedAtPosition(const WebCore::FloatPoint& position)
820 {
821     process().send(Messages::WebPage::InspectorNodeSearchEndedAtPosition(position), m_pageID);
822 }
823
824 void WebPageProxy::blurAssistedNode()
825 {
826     process().send(Messages::WebPage::BlurAssistedNode(), m_pageID);
827 }
828
829 FloatSize WebPageProxy::screenSize()
830 {
831     return WebCore::screenSize();
832 }
833
834 FloatSize WebPageProxy::availableScreenSize()
835 {
836     return WebCore::availableScreenSize();
837 }
838     
839 float WebPageProxy::textAutosizingWidth()
840 {
841     return WebCore::screenSize().width();
842 }
843
844 void WebPageProxy::dynamicViewportUpdateChangedTarget(double newScale, const WebCore::FloatPoint& newScrollPosition, uint64_t dynamicViewportSizeUpdateID)
845 {
846     if (dynamicViewportSizeUpdateID != m_currentDynamicViewportSizeUpdateID)
847         return;
848
849     if (m_dynamicViewportSizeUpdateWaitingForTarget) {
850         m_dynamicViewportSizeUpdateLayerTreeTransactionID = downcast<RemoteLayerTreeDrawingAreaProxy>(*drawingArea()).nextLayerTreeTransactionID();
851         m_dynamicViewportSizeUpdateWaitingForTarget = false;
852         m_pageClient.dynamicViewportUpdateChangedTarget(newScale, newScrollPosition, m_dynamicViewportSizeUpdateLayerTreeTransactionID);
853     }
854 }
855
856 void WebPageProxy::couldNotRestorePageState()
857 {
858     m_pageClient.couldNotRestorePageState();
859 }
860
861 void WebPageProxy::restorePageState(const WebCore::FloatPoint& scrollPosition, const WebCore::FloatPoint& scrollOrigin, const WebCore::FloatSize& obscuredInsetOnSave, double scale)
862 {
863     m_pageClient.restorePageState(scrollPosition, scrollOrigin, obscuredInsetOnSave, scale);
864 }
865
866 void WebPageProxy::restorePageCenterAndScale(const WebCore::FloatPoint& center, double scale)
867 {
868     m_pageClient.restorePageCenterAndScale(center, scale);
869 }
870
871 void WebPageProxy::didGetTapHighlightGeometries(uint64_t requestID, const WebCore::Color& color, const Vector<WebCore::FloatQuad>& highlightedQuads, const WebCore::IntSize& topLeftRadius, const WebCore::IntSize& topRightRadius, const WebCore::IntSize& bottomLeftRadius, const WebCore::IntSize& bottomRightRadius)
872 {
873     m_pageClient.didGetTapHighlightGeometries(requestID, color, highlightedQuads, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius);
874 }
875
876 void WebPageProxy::startAssistingNode(const AssistedNodeInformation& information, bool userIsInteracting, bool blurPreviousNode, const UserData& userData)
877 {
878     API::Object* userDataObject = process().transformHandlesToObjects(userData.object()).get();
879     if (m_editorState.isMissingPostLayoutData) {
880         m_deferredNodeAssistanceArguments = std::make_unique<NodeAssistanceArguments>(NodeAssistanceArguments { information, userIsInteracting, blurPreviousNode, userDataObject });
881         m_hasDeferredStartAssistingNode = true;
882         return;
883     }
884
885     m_pageClient.startAssistingNode(information, userIsInteracting, blurPreviousNode, userDataObject);
886 }
887
888 void WebPageProxy::stopAssistingNode()
889 {
890     if (m_hasDeferredStartAssistingNode) {
891         m_hasDeferredStartAssistingNode = false;
892         m_deferredNodeAssistanceArguments = nullptr;
893     }
894     m_pageClient.stopAssistingNode();
895 }
896
897 void WebPageProxy::showInspectorHighlight(const WebCore::Highlight& highlight)
898 {
899     m_pageClient.showInspectorHighlight(highlight);
900 }
901
902 void WebPageProxy::hideInspectorHighlight()
903 {
904     m_pageClient.hideInspectorHighlight();
905 }
906
907 void WebPageProxy::showInspectorIndication()
908 {
909     m_pageClient.showInspectorIndication();
910 }
911
912 void WebPageProxy::hideInspectorIndication()
913 {
914     m_pageClient.hideInspectorIndication();
915 }
916
917 void WebPageProxy::enableInspectorNodeSearch()
918 {
919     m_pageClient.enableInspectorNodeSearch();
920 }
921
922 void WebPageProxy::disableInspectorNodeSearch()
923 {
924     m_pageClient.disableInspectorNodeSearch();
925 }
926
927 void WebPageProxy::focusNextAssistedNode(bool isForward, std::function<void (CallbackBase::Error)> callbackFunction)
928 {
929     if (!isValid()) {
930         callbackFunction(CallbackBase::Error::Unknown);
931         return;
932     }
933     
934     uint64_t callbackID = m_callbacks.put(WTFMove(callbackFunction), m_process->throttler().backgroundActivityToken());
935     process().send(Messages::WebPage::FocusNextAssistedNode(isForward, callbackID), m_pageID);
936 }
937
938 void WebPageProxy::setAssistedNodeValue(const String& value)
939 {
940     process().send(Messages::WebPage::SetAssistedNodeValue(value), m_pageID);
941 }
942
943 void WebPageProxy::setAssistedNodeValueAsNumber(double value)
944 {
945     process().send(Messages::WebPage::SetAssistedNodeValueAsNumber(value), m_pageID);
946 }
947
948 void WebPageProxy::setAssistedNodeSelectedIndex(uint32_t index, bool allowMultipleSelection)
949 {
950     process().send(Messages::WebPage::SetAssistedNodeSelectedIndex(index, allowMultipleSelection), m_pageID);
951 }
952
953 void WebPageProxy::didPerformDictionaryLookup(const DictionaryPopupInfo&)
954 {
955     notImplemented();
956 }
957
958 void WebPageProxy::savePDFToTemporaryFolderAndOpenWithNativeApplication(const String&, const String&, const IPC::DataReference&, const String&)
959 {
960     notImplemented();
961 }
962
963 void WebPageProxy::savePDFToTemporaryFolderAndOpenWithNativeApplicationRaw(const String&, const String&, const uint8_t*, unsigned long, const String&)
964 {
965     notImplemented();
966 }
967
968 void WebPageProxy::openPDFFromTemporaryFolderWithNativeApplication(const String&)
969 {
970     notImplemented();
971 }
972
973 void WebPageProxy::setAcceleratedCompositingRootLayer(LayerOrView* rootLayer)
974 {
975     m_pageClient.setAcceleratedCompositingRootLayer(rootLayer);
976 }
977
978 void WebPageProxy::showPlaybackTargetPicker(bool hasVideo, const IntRect& elementRect)
979 {
980     m_pageClient.showPlaybackTargetPicker(hasVideo, elementRect);
981 }
982
983 void WebPageProxy::zoomToRect(FloatRect rect, double minimumScale, double maximumScale)
984 {
985     m_pageClient.zoomToRect(rect, minimumScale, maximumScale);
986 }
987
988 void WebPageProxy::commitPotentialTapFailed()
989 {
990     m_pageClient.commitPotentialTapFailed();
991 }
992
993 void WebPageProxy::didNotHandleTapAsClick(const WebCore::IntPoint& point)
994 {
995     m_pageClient.didNotHandleTapAsClick(point);
996     m_uiClient->didNotHandleTapAsClick(point);
997 }
998
999 void WebPageProxy::disableDoubleTapGesturesDuringTapIfNecessary(uint64_t requestID)
1000 {
1001     m_pageClient.disableDoubleTapGesturesDuringTapIfNecessary(requestID);
1002 }
1003
1004 uint32_t WebPageProxy::computePagesForPrintingAndDrawToPDF(uint64_t frameID, const PrintInfo& printInfo, DrawToPDFCallback::CallbackFunction&& callback)
1005 {
1006     if (!isValid()) {
1007         callback(IPC::DataReference(), CallbackBase::Error::OwnerWasInvalidated);
1008         return 0;
1009     }
1010
1011     uint32_t pageCount = 0;
1012     uint64_t callbackID = m_callbacks.put(WTFMove(callback), m_process->throttler().backgroundActivityToken());
1013     using Message = Messages::WebPage::ComputePagesForPrintingAndDrawToPDF;
1014     process().sendSync(Message(frameID, printInfo, callbackID), Message::Reply(pageCount), m_pageID);
1015     return pageCount;
1016 }
1017
1018 void WebPageProxy::drawToPDFCallback(const IPC::DataReference& pdfData, uint64_t callbackID)
1019 {
1020     auto callback = m_callbacks.take<DrawToPDFCallback>(callbackID);
1021     RELEASE_ASSERT(callback);
1022     callback->performCallbackWithReturnValue(pdfData);
1023 }
1024
1025 void WebPageProxy::contentSizeCategoryDidChange(const String& contentSizeCategory)
1026 {
1027     process().send(Messages::WebPage::ContentSizeCategoryDidChange(contentSizeCategory), m_pageID);
1028 }
1029
1030 void WebPageProxy::editorStateChanged(const EditorState& editorState)
1031 {
1032     bool couldChangeSecureInputState = m_editorState.isInPasswordField != editorState.isInPasswordField || m_editorState.selectionIsNone;
1033     
1034     m_editorState = editorState;
1035     
1036     // Selection being none is a temporary state when editing. Flipping secure input state too quickly was causing trouble (not fully understood).
1037     if (couldChangeSecureInputState && !editorState.selectionIsNone)
1038         m_pageClient.updateSecureInputState();
1039     
1040     if (editorState.shouldIgnoreCompositionSelectionChange)
1041         return;
1042     
1043     // We always need to notify the client on iOS to make sure the selection is redrawn,
1044     // even during composition to support phrase boundary gesture.
1045     m_pageClient.selectionDidChange();
1046 }
1047
1048 void WebPageProxy::showValidationMessage(const IntRect& anchorClientRect, const String& message)
1049 {
1050     m_validationBubble = m_pageClient.createValidationBubble(message);
1051     m_validationBubble->setAnchorRect(anchorClientRect, uiClient().presentingViewController());
1052
1053     // If we are currently doing a scrolling / zoom animation, then we'll delay showing the validation
1054     // bubble until the animation is over.
1055     if (!m_isScrollingOrZooming)
1056         m_validationBubble->show();
1057 }
1058
1059 void WebPageProxy::setIsScrollingOrZooming(bool isScrollingOrZooming)
1060 {
1061     m_isScrollingOrZooming = isScrollingOrZooming;
1062
1063     // We finished doing the scrolling / zoom animation so we can now show the validation
1064     // bubble if we're supposed to.
1065     if (!m_isScrollingOrZooming && m_validationBubble)
1066         m_validationBubble->show();
1067 }
1068
1069 #if USE(QUICK_LOOK)
1070     
1071 void WebPageProxy::didStartLoadForQuickLookDocumentInMainFrame(const String& fileName, const String& uti)
1072 {
1073     // Ensure that fileName isn't really a path name
1074     static_assert(notFound + 1 == 0, "The following line assumes WTF::notFound equals -1");
1075     if (m_navigationClient)
1076         m_navigationClient->didStartLoadForQuickLookDocumentInMainFrame(fileName.substring(fileName.reverseFind('/') + 1), uti);
1077     else
1078         m_loaderClient->didStartLoadForQuickLookDocumentInMainFrame(fileName.substring(fileName.reverseFind('/') + 1), uti);
1079 }
1080
1081 void WebPageProxy::didFinishLoadForQuickLookDocumentInMainFrame(const QuickLookDocumentData& data)
1082 {
1083     if (m_navigationClient)
1084         m_navigationClient->didFinishLoadForQuickLookDocumentInMainFrame(data);
1085     else
1086         m_loaderClient->didFinishLoadForQuickLookDocumentInMainFrame(data);
1087 }
1088 #endif
1089
1090 } // namespace WebKit
1091
1092 #endif // PLATFORM(IOS)