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