1/*
2 * Copyright (C) 2012, 2013 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 "PageClientImplIOS.h"
28
29#if PLATFORM(IOS)
30
31#import "APIData.h"
32#import "DataReference.h"
33#import "DownloadProxy.h"
34#import "FindIndicator.h"
35#import "InteractionInformationAtPosition.h"
36#import "NativeWebKeyboardEvent.h"
37#import "NavigationState.h"
38#import "ViewSnapshotStore.h"
39#import "WKContentView.h"
40#import "WKContentViewInteraction.h"
41#import "WKWebViewConfigurationInternal.h"
42#import "WKWebViewContentProviderRegistry.h"
43#import "WKWebViewInternal.h"
44#import "WebContextMenuProxy.h"
45#import "WebEditCommandProxy.h"
46#import "WebProcessProxy.h"
47#import "_WKDownloadInternal.h"
48#import <UIKit/UIImagePickerController_Private.h>
49#import <UIKit/UIWebTouchEventsGestureRecognizer.h>
50#import <WebCore/NotImplemented.h>
51#import <WebCore/PlatformScreen.h>
52#import <WebCore/SharedBuffer.h>
53
54#define MESSAGE_CHECK(assertion) MESSAGE_CHECK_BASE(assertion, m_webView->_page->process().connection())
55
56@interface UIView (IPI)
57- (UIScrollView *)_scroller;
58- (CGPoint)accessibilityConvertPointFromSceneReferenceCoordinates:(CGPoint)point;
59- (CGRect)accessibilityConvertRectToSceneReferenceCoordinates:(CGRect)rect;
60@end
61
62using namespace WebCore;
63using namespace WebKit;
64
65@interface WKEditCommandObjC : NSObject
66{
67    RefPtr<WebEditCommandProxy> m_command;
68}
69- (id)initWithWebEditCommandProxy:(PassRefPtr<WebEditCommandProxy>)command;
70- (WebEditCommandProxy*)command;
71@end
72
73@interface WKEditorUndoTargetObjC : NSObject
74- (void)undoEditing:(id)sender;
75- (void)redoEditing:(id)sender;
76@end
77
78@implementation WKEditCommandObjC
79
80- (id)initWithWebEditCommandProxy:(PassRefPtr<WebEditCommandProxy>)command
81{
82    self = [super init];
83    if (!self)
84        return nil;
85
86    m_command = command;
87    return self;
88}
89
90- (WebEditCommandProxy *)command
91{
92    return m_command.get();
93}
94
95@end
96
97@implementation WKEditorUndoTargetObjC
98
99- (void)undoEditing:(id)sender
100{
101    ASSERT([sender isKindOfClass:[WKEditCommandObjC class]]);
102    [sender command]->unapply();
103}
104
105- (void)redoEditing:(id)sender
106{
107    ASSERT([sender isKindOfClass:[WKEditCommandObjC class]]);
108    [sender command]->reapply();
109}
110
111@end
112
113namespace WebKit {
114
115PageClientImpl::PageClientImpl(WKContentView *contentView, WKWebView *webView)
116    : m_contentView(contentView)
117    , m_webView(webView)
118    , m_undoTarget(adoptNS([[WKEditorUndoTargetObjC alloc] init]))
119{
120}
121
122PageClientImpl::~PageClientImpl()
123{
124}
125
126std::unique_ptr<DrawingAreaProxy> PageClientImpl::createDrawingAreaProxy()
127{
128    return [m_contentView _createDrawingAreaProxy];
129}
130
131void PageClientImpl::setViewNeedsDisplay(const IntRect& rect)
132{
133    ASSERT_NOT_REACHED();
134}
135
136void PageClientImpl::displayView()
137{
138    ASSERT_NOT_REACHED();
139}
140
141bool PageClientImpl::canScrollView()
142{
143    notImplemented();
144    return false;
145}
146
147void PageClientImpl::scrollView(const IntRect&, const IntSize&)
148{
149    ASSERT_NOT_REACHED();
150}
151
152void PageClientImpl::requestScroll(const FloatPoint& scrollPosition, bool isProgrammaticScroll)
153{
154    UNUSED_PARAM(isProgrammaticScroll);
155    [m_webView _scrollToContentOffset:scrollPosition];
156}
157
158IntSize PageClientImpl::viewSize()
159{
160    if (UIScrollView *scroller = [m_contentView _scroller])
161        return IntSize(scroller.bounds.size);
162
163    return IntSize(m_contentView.bounds.size);
164}
165
166bool PageClientImpl::isViewWindowActive()
167{
168    // FIXME: https://bugs.webkit.org/show_bug.cgi?id=133098
169    return isViewVisible();
170}
171
172bool PageClientImpl::isViewFocused()
173{
174    // FIXME: https://bugs.webkit.org/show_bug.cgi?id=133098
175    return isViewWindowActive();
176}
177
178bool PageClientImpl::isViewVisible()
179{
180    return isViewInWindow() && !m_contentView.isBackground;
181}
182
183bool PageClientImpl::isViewInWindow()
184{
185    // FIXME: in WebKitTestRunner, m_webView is nil, so check the content view instead.
186    if (m_webView)
187        return [m_webView window];
188
189    return [m_contentView window];
190}
191
192bool PageClientImpl::isViewVisibleOrOccluded()
193{
194    return isViewVisible();
195}
196
197bool PageClientImpl::isVisuallyIdle()
198{
199    return !isViewVisible();
200}
201
202void PageClientImpl::processDidExit()
203{
204    [m_contentView _processDidExit];
205    [m_webView _processDidExit];
206}
207
208void PageClientImpl::didRelaunchProcess()
209{
210    [m_contentView _didRelaunchProcess];
211    [m_webView _didRelaunchProcess];
212}
213
214void PageClientImpl::pageClosed()
215{
216    notImplemented();
217}
218
219void PageClientImpl::preferencesDidChange()
220{
221    notImplemented();
222}
223
224void PageClientImpl::toolTipChanged(const String&, const String&)
225{
226    notImplemented();
227}
228
229bool PageClientImpl::decidePolicyForGeolocationPermissionRequest(WebFrameProxy& frame, WebSecurityOrigin& origin, GeolocationPermissionRequestProxy& request)
230{
231    [m_contentView _decidePolicyForGeolocationRequestFromOrigin:origin frame:frame request:request];
232    return true;
233}
234
235void PageClientImpl::didCommitLoadForMainFrame(const String& mimeType, bool useCustomContentProvider)
236{
237    [m_webView _setHasCustomContentView:useCustomContentProvider loadedMIMEType:mimeType];
238    [m_contentView _didCommitLoadForMainFrame];
239}
240
241void PageClientImpl::handleDownloadRequest(DownloadProxy* download)
242{
243    ASSERT_ARG(download, download);
244    ASSERT([download->wrapper() isKindOfClass:[_WKDownload class]]);
245    [static_cast<_WKDownload *>(download->wrapper()) setOriginatingWebView:m_webView];
246}
247
248void PageClientImpl::didChangeViewportMetaTagWidth(float newWidth)
249{
250    [m_webView _setViewportMetaTagWidth:newWidth];
251}
252
253void PageClientImpl::setUsesMinimalUI(bool usesMinimalUI)
254{
255    [m_webView _setUsesMinimalUI:usesMinimalUI];
256}
257
258double PageClientImpl::minimumZoomScale() const
259{
260    if (UIScrollView *scroller = [m_webView scrollView])
261        return scroller.minimumZoomScale;
262
263    return 1;
264}
265
266WebCore::FloatSize PageClientImpl::contentsSize() const
267{
268    return FloatSize([m_contentView bounds].size);
269}
270
271void PageClientImpl::setCursor(const Cursor&)
272{
273    notImplemented();
274}
275
276void PageClientImpl::setCursorHiddenUntilMouseMoves(bool)
277{
278    notImplemented();
279}
280
281void PageClientImpl::didChangeViewportProperties(const ViewportAttributes&)
282{
283    notImplemented();
284}
285
286void PageClientImpl::registerEditCommand(PassRefPtr<WebEditCommandProxy> prpCommand, WebPageProxy::UndoOrRedo undoOrRedo)
287{
288    RefPtr<WebEditCommandProxy> command = prpCommand;
289
290    RetainPtr<WKEditCommandObjC> commandObjC = adoptNS([[WKEditCommandObjC alloc] initWithWebEditCommandProxy:command]);
291    String actionName = WebEditCommandProxy::nameForEditAction(command->editAction());
292
293    NSUndoManager *undoManager = [m_contentView undoManager];
294    [undoManager registerUndoWithTarget:m_undoTarget.get() selector:((undoOrRedo == WebPageProxy::Undo) ? @selector(undoEditing:) : @selector(redoEditing:)) object:commandObjC.get()];
295    if (!actionName.isEmpty())
296        [undoManager setActionName:(NSString *)actionName];
297}
298
299#if USE(INSERTION_UNDO_GROUPING)
300void PageClientImpl::registerInsertionUndoGrouping()
301{
302    notImplemented();
303}
304#endif
305
306void PageClientImpl::clearAllEditCommands()
307{
308    [[m_contentView undoManager] removeAllActionsWithTarget:m_undoTarget.get()];
309}
310
311bool PageClientImpl::canUndoRedo(WebPageProxy::UndoOrRedo undoOrRedo)
312{
313    return (undoOrRedo == WebPageProxy::Undo) ? [[m_contentView undoManager] canUndo] : [[m_contentView undoManager] canRedo];
314}
315
316void PageClientImpl::executeUndoRedo(WebPageProxy::UndoOrRedo undoOrRedo)
317{
318    return (undoOrRedo == WebPageProxy::Undo) ? [[m_contentView undoManager] undo] : [[m_contentView undoManager] redo];
319}
320
321void PageClientImpl::accessibilityWebProcessTokenReceived(const IPC::DataReference& data)
322{
323    NSData *remoteToken = [NSData dataWithBytes:data.data() length:data.size()];
324    [m_contentView _setAccessibilityWebProcessToken:remoteToken];
325}
326
327bool PageClientImpl::interpretKeyEvent(const NativeWebKeyboardEvent& event, bool isCharEvent)
328{
329    return [m_contentView _interpretKeyEvent:event.nativeEvent() isCharEvent:isCharEvent];
330}
331
332void PageClientImpl::positionInformationDidChange(const InteractionInformationAtPosition& info)
333{
334    [m_contentView _positionInformationDidChange:info];
335}
336
337void PageClientImpl::saveImageToLibrary(PassRefPtr<SharedBuffer> imageBuffer)
338{
339    RetainPtr<NSData> imageData = imageBuffer->createNSData();
340    UIImageDataWriteToSavedPhotosAlbum(imageData.get(), nil, NULL, NULL);
341}
342
343bool PageClientImpl::executeSavedCommandBySelector(const String&)
344{
345    notImplemented();
346    return false;
347}
348
349void PageClientImpl::setDragImage(const IntPoint&, PassRefPtr<ShareableBitmap>, bool)
350{
351    notImplemented();
352}
353
354void PageClientImpl::selectionDidChange()
355{
356    [m_contentView _selectionChanged];
357}
358
359void PageClientImpl::updateSecureInputState()
360{
361    notImplemented();
362}
363
364void PageClientImpl::resetSecureInputState()
365{
366    notImplemented();
367}
368
369void PageClientImpl::notifyInputContextAboutDiscardedComposition()
370{
371    notImplemented();
372}
373
374void PageClientImpl::makeFirstResponder()
375{
376    notImplemented();
377}
378
379FloatRect PageClientImpl::convertToDeviceSpace(const FloatRect& rect)
380{
381    notImplemented();
382    return FloatRect();
383}
384
385FloatRect PageClientImpl::convertToUserSpace(const FloatRect& rect)
386{
387    notImplemented();
388    return FloatRect();
389}
390
391IntPoint PageClientImpl::screenToRootView(const IntPoint& point)
392{
393    return IntPoint([m_contentView convertPoint:point fromView:nil]);
394}
395
396IntRect PageClientImpl::rootViewToScreen(const IntRect& rect)
397{
398    return enclosingIntRect([m_contentView convertRect:rect toView:nil]);
399}
400
401IntPoint PageClientImpl::accessibilityScreenToRootView(const IntPoint& point)
402{
403    CGPoint rootViewPoint = point;
404    if ([m_contentView respondsToSelector:@selector(accessibilityConvertPointFromSceneReferenceCoordinates:)])
405        rootViewPoint = [m_contentView accessibilityConvertPointFromSceneReferenceCoordinates:rootViewPoint];
406    return IntPoint(rootViewPoint);
407}
408
409IntRect PageClientImpl::rootViewToAccessibilityScreen(const IntRect& rect)
410{
411    CGRect rootViewRect = rect;
412    if ([m_contentView respondsToSelector:@selector(accessibilityConvertRectToSceneReferenceCoordinates:)])
413        rootViewRect = [m_contentView accessibilityConvertRectToSceneReferenceCoordinates:rootViewRect];
414    return enclosingIntRect(rootViewRect);
415}
416
417void PageClientImpl::doneWithKeyEvent(const NativeWebKeyboardEvent& event, bool)
418{
419    [m_contentView _didHandleKeyEvent:event.nativeEvent()];
420}
421
422#if ENABLE(TOUCH_EVENTS)
423void PageClientImpl::doneWithTouchEvent(const NativeWebTouchEvent& nativeWebtouchEvent, bool eventHandled)
424{
425    [m_contentView _webTouchEvent:nativeWebtouchEvent preventsNativeGestures:eventHandled];
426}
427#endif
428
429PassRefPtr<WebPopupMenuProxy> PageClientImpl::createPopupMenuProxy(WebPageProxy*)
430{
431    notImplemented();
432    return 0;
433}
434
435PassRefPtr<WebContextMenuProxy> PageClientImpl::createContextMenuProxy(WebPageProxy*)
436{
437    notImplemented();
438    return 0;
439}
440
441void PageClientImpl::setFindIndicator(PassRefPtr<FindIndicator> findIndicator, bool fadeOut, bool animate)
442{
443}
444
445void PageClientImpl::enterAcceleratedCompositingMode(const LayerTreeContext& layerTreeContext)
446{
447}
448
449void PageClientImpl::exitAcceleratedCompositingMode()
450{
451    notImplemented();
452}
453
454void PageClientImpl::updateAcceleratedCompositingMode(const LayerTreeContext&)
455{
456}
457
458void PageClientImpl::setAcceleratedCompositingRootLayer(LayerOrView *rootLayer)
459{
460    [m_contentView _setAcceleratedCompositingRootView:rootLayer];
461}
462
463LayerOrView *PageClientImpl::acceleratedCompositingRootLayer() const
464{
465    notImplemented();
466    return nullptr;
467}
468
469PassRefPtr<ViewSnapshot> PageClientImpl::takeViewSnapshot()
470{
471    return [m_webView _takeViewSnapshot];
472}
473
474void PageClientImpl::wheelEventWasNotHandledByWebCore(const NativeWebWheelEvent& event)
475{
476    notImplemented();
477}
478
479void PageClientImpl::commitPotentialTapFailed()
480{
481    [m_contentView _commitPotentialTapFailed];
482}
483
484void PageClientImpl::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)
485{
486    [m_contentView _didGetTapHighlightForRequest:requestID color:color quads:highlightedQuads topLeftRadius:topLeftRadius topRightRadius:topRightRadius bottomLeftRadius:bottomLeftRadius bottomRightRadius:bottomRightRadius];
487}
488
489void PageClientImpl::didCommitLayerTree(const RemoteLayerTreeTransaction& layerTreeTransaction)
490{
491    [m_contentView _didCommitLayerTree:layerTreeTransaction];
492}
493
494void PageClientImpl::dynamicViewportUpdateChangedTarget(double newScale, const WebCore::FloatPoint& newScrollPosition, uint64_t nextValidLayerTreeTransactionID)
495{
496    [m_webView _dynamicViewportUpdateChangedTargetToScale:newScale position:newScrollPosition nextValidLayerTreeTransactionID:nextValidLayerTreeTransactionID];
497}
498
499void PageClientImpl::restorePageState(const WebCore::FloatRect& exposedRect, double scale)
500{
501    [m_webView _restorePageStateToExposedRect:exposedRect scale:scale];
502}
503
504void PageClientImpl::restorePageCenterAndScale(const WebCore::FloatPoint& center, double scale)
505{
506    [m_webView _restorePageStateToUnobscuredCenter:center scale:scale];
507}
508
509void PageClientImpl::startAssistingNode(const AssistedNodeInformation& nodeInformation, bool userIsInteracting, bool blurPreviousNode, API::Object* userData)
510{
511    MESSAGE_CHECK(!userData || userData->type() == API::Object::Type::Data);
512
513    NSObject <NSSecureCoding> *userObject = nil;
514    if (API::Data* data = static_cast<API::Data*>(userData)) {
515        auto nsData = adoptNS([[NSData alloc] initWithBytesNoCopy:const_cast<void*>(static_cast<const void*>(data->bytes())) length:data->size() freeWhenDone:NO]);
516        auto unarchiver = adoptNS([[NSKeyedUnarchiver alloc] initForReadingWithData:nsData.get()]);
517        [unarchiver setRequiresSecureCoding:YES];
518        @try {
519            userObject = [unarchiver decodeObjectOfClass:[NSObject class] forKey:@"userObject"];
520        } @catch (NSException *exception) {
521            LOG_ERROR("Failed to decode user data: %@", exception);
522        }
523    }
524
525    [m_contentView _startAssistingNode:nodeInformation userIsInteracting:userIsInteracting blurPreviousNode:blurPreviousNode userObject:userObject];
526}
527
528bool PageClientImpl::isAssistingNode()
529{
530    return [m_contentView isAssistingNode];
531}
532
533void PageClientImpl::stopAssistingNode()
534{
535    [m_contentView _stopAssistingNode];
536}
537
538void PageClientImpl::didUpdateBlockSelectionWithTouch(uint32_t touch, uint32_t flags, float growThreshold, float shrinkThreshold)
539{
540    [m_contentView _didUpdateBlockSelectionWithTouch:(SelectionTouch)touch withFlags:(SelectionFlags)flags growThreshold:growThreshold shrinkThreshold:shrinkThreshold];
541}
542
543void PageClientImpl::showPlaybackTargetPicker(bool hasVideo, const IntRect& elementRect)
544{
545    [m_contentView _showPlaybackTargetPicker:hasVideo fromRect:elementRect];
546}
547
548bool PageClientImpl::handleRunOpenPanel(WebPageProxy*, WebFrameProxy*, WebOpenPanelParameters* parameters, WebOpenPanelResultListenerProxy* listener)
549{
550    [m_contentView _showRunOpenPanel:parameters resultListener:listener];
551    return true;
552}
553
554#if ENABLE(INSPECTOR)
555void PageClientImpl::showInspectorHighlight(const WebCore::Highlight& highlight)
556{
557    [m_contentView _showInspectorHighlight:highlight];
558}
559
560void PageClientImpl::hideInspectorHighlight()
561{
562    [m_contentView _hideInspectorHighlight];
563}
564
565void PageClientImpl::showInspectorIndication()
566{
567    [m_contentView setShowingInspectorIndication:YES];
568}
569
570void PageClientImpl::hideInspectorIndication()
571{
572    [m_contentView setShowingInspectorIndication:NO];
573}
574
575void PageClientImpl::enableInspectorNodeSearch()
576{
577    [m_contentView _enableInspectorNodeSearch];
578}
579
580void PageClientImpl::disableInspectorNodeSearch()
581{
582    [m_contentView _disableInspectorNodeSearch];
583}
584#endif
585
586#if ENABLE(FULLSCREEN_API)
587
588WebFullScreenManagerProxyClient& PageClientImpl::fullScreenManagerProxyClient()
589{
590    return *this;
591}
592
593// WebFullScreenManagerProxyClient
594
595void PageClientImpl::closeFullScreenManager()
596{
597}
598
599bool PageClientImpl::isFullScreen()
600{
601    return false;
602}
603
604void PageClientImpl::enterFullScreen()
605{
606}
607
608void PageClientImpl::exitFullScreen()
609{
610}
611
612void PageClientImpl::beganEnterFullScreen(const IntRect&, const IntRect&)
613{
614}
615
616void PageClientImpl::beganExitFullScreen(const IntRect&, const IntRect&)
617{
618}
619
620#endif // ENABLE(FULLSCREEN_API)
621
622void PageClientImpl::didFinishLoadingDataForCustomContentProvider(const String& suggestedFilename, const IPC::DataReference& dataReference)
623{
624    RetainPtr<NSData> data = adoptNS([[NSData alloc] initWithBytes:dataReference.data() length:dataReference.size()]);
625    [m_webView _didFinishLoadingDataForCustomContentProviderWithSuggestedFilename:suggestedFilename data:data.get()];
626}
627
628void PageClientImpl::zoomToRect(FloatRect rect, double minimumScale, double maximumScale)
629{
630    [m_contentView _zoomToRect:rect withOrigin:rect.center() fitEntireRect:YES minimumScale:minimumScale maximumScale:maximumScale minimumScrollDistance:0];
631}
632
633void PageClientImpl::overflowScrollViewWillStartPanGesture()
634{
635    [m_contentView scrollViewWillStartPanOrPinchGesture];
636}
637
638void PageClientImpl::overflowScrollViewDidScroll()
639{
640    [m_contentView _didScroll];
641}
642
643void PageClientImpl::overflowScrollWillStartScroll()
644{
645    [m_contentView _overflowScrollingWillBegin];
646}
647
648void PageClientImpl::overflowScrollDidEndScroll()
649{
650    [m_contentView _overflowScrollingDidEnd];
651}
652
653void PageClientImpl::didFinishDrawingPagesToPDF(const IPC::DataReference& pdfData)
654{
655    RetainPtr<CFDataRef> data = adoptCF(CFDataCreate(kCFAllocatorDefault, pdfData.data(), pdfData.size()));
656    RetainPtr<CGDataProviderRef> dataProvider = adoptCF(CGDataProviderCreateWithCFData(data.get()));
657    m_webView._printedDocument = adoptCF(CGPDFDocumentCreateWithProvider(dataProvider.get())).get();
658}
659
660Vector<String> PageClientImpl::mimeTypesWithCustomContentProviders()
661{
662    return m_webView.configuration._contentProviderRegistry._mimeTypesWithCustomContentProviders;
663}
664
665void PageClientImpl::navigationGestureDidBegin()
666{
667    NavigationState::fromWebPage(*m_webView->_page).navigationGestureDidBegin();
668}
669
670void PageClientImpl::navigationGestureWillEnd(bool willNavigate, WebBackForwardListItem& item)
671{
672    NavigationState::fromWebPage(*m_webView->_page).navigationGestureWillEnd(willNavigate, item);
673}
674
675void PageClientImpl::navigationGestureDidEnd(bool willNavigate, WebBackForwardListItem& item)
676{
677    NavigationState::fromWebPage(*m_webView->_page).navigationGestureDidEnd(willNavigate, item);
678}
679
680void PageClientImpl::willRecordNavigationSnapshot(WebBackForwardListItem& item)
681{
682    NavigationState::fromWebPage(*m_webView->_page).willRecordNavigationSnapshot(item);
683}
684
685void PageClientImpl::didFirstVisuallyNonEmptyLayoutForMainFrame()
686{
687}
688
689void PageClientImpl::didFinishLoadForMainFrame()
690{
691}
692
693void PageClientImpl::didSameDocumentNavigationForMainFrame(SameDocumentNavigationType)
694{
695}
696
697} // namespace WebKit
698
699#endif // PLATFORM(IOS)
700