1/*
2 * Copyright (C) 2010, 2011 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 "PageClientImpl.h"
28
29#if PLATFORM(MAC)
30
31#import "AttributedString.h"
32#import "ColorSpaceData.h"
33#import "DataReference.h"
34#import "DictionaryPopupInfo.h"
35#import "DownloadProxy.h"
36#import "FindIndicator.h"
37#import "NativeWebKeyboardEvent.h"
38#import "NativeWebWheelEvent.h"
39#import "NavigationState.h"
40#import "StringUtilities.h"
41#import "ViewSnapshotStore.h"
42#import "WKAPICast.h"
43#import "WKFullScreenWindowController.h"
44#import "WKStringCF.h"
45#import "WKViewInternal.h"
46#import "WKWebViewInternal.h"
47#import "WebColorPickerMac.h"
48#import "WebContextMenuProxyMac.h"
49#import "WebEditCommandProxy.h"
50#import "WebPopupMenuProxyMac.h"
51#import "WindowServerConnection.h"
52#import "_WKDownloadInternal.h"
53#import "_WKThumbnailView.h"
54#import <WebCore/AlternativeTextUIController.h>
55#import <WebCore/BitmapImage.h>
56#import <WebCore/Cursor.h>
57#import <WebCore/FloatRect.h>
58#import <WebCore/GraphicsContext.h>
59#import <WebCore/Image.h>
60#import <WebCore/KeyboardEvent.h>
61#import <WebCore/NotImplemented.h>
62#import <WebCore/SharedBuffer.h>
63#import <WebCore/TextUndoInsertionMarkupMac.h>
64#import <WebKitSystemInterface.h>
65#import <wtf/text/CString.h>
66#import <wtf/text/WTFString.h>
67
68#if USE(DICTATION_ALTERNATIVES)
69#import <AppKit/NSTextAlternatives.h>
70#endif
71
72@interface NSApplication (WebNSApplicationDetails)
73- (NSCursor *)_cursorRectCursor;
74@end
75
76#if HAVE(OUT_OF_PROCESS_LAYER_HOSTING)
77@interface NSWindow (WebNSWindowDetails)
78- (BOOL)_hostsLayersInWindowServer;
79@end
80#endif
81
82using namespace WebCore;
83using namespace WebKit;
84
85@interface WKEditCommandObjC : NSObject
86{
87    RefPtr<WebEditCommandProxy> m_command;
88}
89- (id)initWithWebEditCommandProxy:(PassRefPtr<WebEditCommandProxy>)command;
90- (WebEditCommandProxy*)command;
91@end
92
93@interface WKEditorUndoTargetObjC : NSObject
94- (void)undoEditing:(id)sender;
95- (void)redoEditing:(id)sender;
96@end
97
98@implementation WKEditCommandObjC
99
100- (id)initWithWebEditCommandProxy:(PassRefPtr<WebEditCommandProxy>)command
101{
102    self = [super init];
103    if (!self)
104        return nil;
105
106    m_command = command;
107    return self;
108}
109
110- (WebEditCommandProxy*)command
111{
112    return m_command.get();
113}
114
115@end
116
117@implementation WKEditorUndoTargetObjC
118
119- (void)undoEditing:(id)sender
120{
121    ASSERT([sender isKindOfClass:[WKEditCommandObjC class]]);
122    [sender command]->unapply();
123}
124
125- (void)redoEditing:(id)sender
126{
127    ASSERT([sender isKindOfClass:[WKEditCommandObjC class]]);
128    [sender command]->reapply();
129}
130
131@end
132
133namespace WebKit {
134
135PageClientImpl::PageClientImpl(WKView* wkView, WKWebView *webView)
136    : m_wkView(wkView)
137    , m_webView(webView)
138    , m_undoTarget(adoptNS([[WKEditorUndoTargetObjC alloc] init]))
139#if USE(DICTATION_ALTERNATIVES)
140    , m_alternativeTextUIController(adoptPtr(new AlternativeTextUIController))
141#endif
142{
143#if !WK_API_ENABLED
144    ASSERT_UNUSED(m_webView, !m_webView);
145#endif
146}
147
148PageClientImpl::~PageClientImpl()
149{
150}
151
152std::unique_ptr<DrawingAreaProxy> PageClientImpl::createDrawingAreaProxy()
153{
154    return [m_wkView _createDrawingAreaProxy];
155}
156
157void PageClientImpl::setViewNeedsDisplay(const WebCore::IntRect& rect)
158{
159    ASSERT_NOT_REACHED();
160}
161
162void PageClientImpl::displayView()
163{
164    ASSERT_NOT_REACHED();
165}
166
167bool PageClientImpl::canScrollView()
168{
169    return false;
170}
171
172void PageClientImpl::scrollView(const IntRect& scrollRect, const IntSize& scrollOffset)
173{
174    ASSERT_NOT_REACHED();
175}
176
177void PageClientImpl::requestScroll(const FloatPoint& scrollPosition, bool isProgrammaticScroll)
178{
179    ASSERT_NOT_REACHED();
180}
181
182IntSize PageClientImpl::viewSize()
183{
184    return IntSize([m_wkView bounds].size);
185}
186
187NSView *PageClientImpl::activeView() const
188{
189#if WK_API_ENABLED
190    return m_wkView._thumbnailView ? (NSView *)m_wkView._thumbnailView : (NSView *)m_wkView;
191#else
192    return m_wkView;
193#endif
194}
195
196bool PageClientImpl::isViewWindowActive()
197{
198    NSWindow *activeViewWindow = activeView().window;
199    return activeViewWindow.isKeyWindow || [NSApp keyWindow] == activeViewWindow;
200}
201
202bool PageClientImpl::isViewFocused()
203{
204    return [m_wkView _isFocused];
205}
206
207void PageClientImpl::makeFirstResponder()
208{
209     [[m_wkView window] makeFirstResponder:m_wkView];
210}
211
212bool PageClientImpl::isViewVisible()
213{
214    NSView *activeView = this->activeView();
215    NSWindow *activeViewWindow = activeView.window;
216
217    if (!activeViewWindow)
218        return false;
219
220    if (!activeViewWindow.isVisible)
221        return false;
222
223#if __MAC_OS_X_VERSION_MIN_REQUIRED <= 1080
224    // Mountain Lion and previous do not support occlusion notifications, and as such will
225    // continue to report as "visible" when not on the active space.
226    if (!activeViewWindow.isOnActiveSpace)
227        return false;
228#endif
229
230    if (activeView.isHiddenOrHasHiddenAncestor)
231        return false;
232
233#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
234    if ([m_wkView windowOcclusionDetectionEnabled] && (activeViewWindow.occlusionState & NSWindowOcclusionStateVisible) != NSWindowOcclusionStateVisible)
235        return false;
236#endif
237
238    return true;
239}
240
241bool PageClientImpl::isViewVisibleOrOccluded()
242{
243    return activeView().window.isVisible;
244}
245
246bool PageClientImpl::isViewInWindow()
247{
248    return activeView().window;
249}
250
251bool PageClientImpl::isVisuallyIdle()
252{
253    return WindowServerConnection::shared().applicationWindowModificationsHaveStopped() || !isViewVisible();
254}
255
256LayerHostingMode PageClientImpl::viewLayerHostingMode()
257{
258#if HAVE(OUT_OF_PROCESS_LAYER_HOSTING)
259    if ([activeView().window _hostsLayersInWindowServer])
260        return LayerHostingMode::OutOfProcess;
261#endif
262    return LayerHostingMode::InProcess;
263}
264
265void PageClientImpl::viewWillMoveToAnotherWindow()
266{
267    clearAllEditCommands();
268}
269
270ColorSpaceData PageClientImpl::colorSpace()
271{
272    return [m_wkView _colorSpace];
273}
274
275void PageClientImpl::processDidExit()
276{
277    [m_wkView _processDidExit];
278}
279
280void PageClientImpl::pageClosed()
281{
282    [m_wkView _pageClosed];
283#if USE(DICTATION_ALTERNATIVES)
284    m_alternativeTextUIController->clear();
285#endif
286}
287
288void PageClientImpl::didRelaunchProcess()
289{
290    [m_wkView _didRelaunchProcess];
291}
292
293void PageClientImpl::preferencesDidChange()
294{
295    [m_wkView _preferencesDidChange];
296}
297
298void PageClientImpl::toolTipChanged(const String& oldToolTip, const String& newToolTip)
299{
300    [m_wkView _toolTipChangedFrom:nsStringFromWebCoreString(oldToolTip) to:nsStringFromWebCoreString(newToolTip)];
301}
302
303void PageClientImpl::didCommitLoadForMainFrame(const String& mimeType, bool useCustomContentProvider)
304{
305}
306
307void PageClientImpl::didFinishLoadingDataForCustomContentProvider(const String& suggestedFilename, const IPC::DataReference& dataReference)
308{
309}
310
311void PageClientImpl::handleDownloadRequest(DownloadProxy* download)
312{
313    ASSERT_ARG(download, download);
314#if WK_API_ENABLED
315    ASSERT([download->wrapper() isKindOfClass:[_WKDownload class]]);
316    [static_cast<_WKDownload *>(download->wrapper()) setOriginatingWebView:m_webView];
317#endif
318}
319
320void PageClientImpl::setCursor(const WebCore::Cursor& cursor)
321{
322    // FIXME: Would be nice to share this code with WebKit1's WebChromeClient.
323
324    if ([NSApp _cursorRectCursor])
325        return;
326
327    if (!m_wkView)
328        return;
329
330    NSWindow *window = [m_wkView window];
331    if (!window)
332        return;
333
334    if ([window windowNumber] != [NSWindow windowNumberAtPoint:[NSEvent mouseLocation] belowWindowWithWindowNumber:0])
335        return;
336
337    NSCursor *platformCursor = cursor.platformCursor();
338    if ([NSCursor currentCursor] == platformCursor)
339        return;
340
341    [platformCursor set];
342}
343
344void PageClientImpl::setCursorHiddenUntilMouseMoves(bool hiddenUntilMouseMoves)
345{
346    [NSCursor setHiddenUntilMouseMoves:hiddenUntilMouseMoves];
347}
348
349void PageClientImpl::didChangeViewportProperties(const WebCore::ViewportAttributes&)
350{
351}
352
353void PageClientImpl::registerEditCommand(PassRefPtr<WebEditCommandProxy> prpCommand, WebPageProxy::UndoOrRedo undoOrRedo)
354{
355    RefPtr<WebEditCommandProxy> command = prpCommand;
356
357    RetainPtr<WKEditCommandObjC> commandObjC = adoptNS([[WKEditCommandObjC alloc] initWithWebEditCommandProxy:command]);
358    String actionName = WebEditCommandProxy::nameForEditAction(command->editAction());
359
360    NSUndoManager *undoManager = [m_wkView undoManager];
361    [undoManager registerUndoWithTarget:m_undoTarget.get() selector:((undoOrRedo == WebPageProxy::Undo) ? @selector(undoEditing:) : @selector(redoEditing:)) object:commandObjC.get()];
362    if (!actionName.isEmpty())
363        [undoManager setActionName:(NSString *)actionName];
364}
365
366#if USE(INSERTION_UNDO_GROUPING)
367void PageClientImpl::registerInsertionUndoGrouping()
368{
369    registerInsertionUndoGroupingWithUndoManager([m_wkView undoManager]);
370}
371#endif
372
373void PageClientImpl::clearAllEditCommands()
374{
375    [[m_wkView undoManager] removeAllActionsWithTarget:m_undoTarget.get()];
376}
377
378bool PageClientImpl::canUndoRedo(WebPageProxy::UndoOrRedo undoOrRedo)
379{
380    return (undoOrRedo == WebPageProxy::Undo) ? [[m_wkView undoManager] canUndo] : [[m_wkView undoManager] canRedo];
381}
382
383void PageClientImpl::executeUndoRedo(WebPageProxy::UndoOrRedo undoOrRedo)
384{
385    return (undoOrRedo == WebPageProxy::Undo) ? [[m_wkView undoManager] undo] : [[m_wkView undoManager] redo];
386}
387
388void PageClientImpl::setDragImage(const IntPoint& clientPosition, PassRefPtr<ShareableBitmap> dragImage, bool isLinkDrag)
389{
390    RetainPtr<CGImageRef> dragCGImage = dragImage->makeCGImage();
391    RetainPtr<NSImage> dragNSImage = adoptNS([[NSImage alloc] initWithCGImage:dragCGImage.get() size:dragImage->size()]);
392
393    [m_wkView _setDragImage:dragNSImage.get() at:clientPosition linkDrag:isLinkDrag];
394}
395
396void PageClientImpl::setPromisedData(const String& pasteboardName, PassRefPtr<SharedBuffer> imageBuffer, const String& filename, const String& extension, const String& title, const String& url, const String& visibleUrl, PassRefPtr<SharedBuffer> archiveBuffer)
397{
398    RefPtr<Image> image = BitmapImage::create();
399    image->setData(imageBuffer.get(), true);
400    [m_wkView _setPromisedData:image.get() withFileName:filename withExtension:extension withTitle:title withURL:url withVisibleURL:visibleUrl withArchive:archiveBuffer.get() forPasteboard:pasteboardName];
401}
402
403void PageClientImpl::updateSecureInputState()
404{
405    [m_wkView _updateSecureInputState];
406}
407
408void PageClientImpl::resetSecureInputState()
409{
410    [m_wkView _resetSecureInputState];
411}
412
413void PageClientImpl::notifyInputContextAboutDiscardedComposition()
414{
415    [m_wkView _notifyInputContextAboutDiscardedComposition];
416}
417
418FloatRect PageClientImpl::convertToDeviceSpace(const FloatRect& rect)
419{
420    return [m_wkView _convertToDeviceSpace:rect];
421}
422
423FloatRect PageClientImpl::convertToUserSpace(const FloatRect& rect)
424{
425    return [m_wkView _convertToUserSpace:rect];
426}
427
428IntPoint PageClientImpl::screenToRootView(const IntPoint& point)
429{
430#pragma clang diagnostic push
431#pragma clang diagnostic ignored "-Wdeprecated-declarations"
432    NSPoint windowCoord = [[m_wkView window] convertScreenToBase:point];
433#pragma clang diagnostic pop
434    return IntPoint([m_wkView convertPoint:windowCoord fromView:nil]);
435}
436
437IntRect PageClientImpl::rootViewToScreen(const IntRect& rect)
438{
439    NSRect tempRect = rect;
440    tempRect = [m_wkView convertRect:tempRect toView:nil];
441#pragma clang diagnostic push
442#pragma clang diagnostic ignored "-Wdeprecated-declarations"
443    tempRect.origin = [[m_wkView window] convertBaseToScreen:tempRect.origin];
444#pragma clang diagnostic pop
445    return enclosingIntRect(tempRect);
446}
447
448void PageClientImpl::doneWithKeyEvent(const NativeWebKeyboardEvent& event, bool eventWasHandled)
449{
450    [m_wkView _doneWithKeyEvent:event.nativeEvent() eventWasHandled:eventWasHandled];
451}
452
453PassRefPtr<WebPopupMenuProxy> PageClientImpl::createPopupMenuProxy(WebPageProxy* page)
454{
455    return WebPopupMenuProxyMac::create(m_wkView, page);
456}
457
458PassRefPtr<WebContextMenuProxy> PageClientImpl::createContextMenuProxy(WebPageProxy* page)
459{
460    return WebContextMenuProxyMac::create(m_wkView, page);
461}
462
463#if ENABLE(INPUT_TYPE_COLOR)
464PassRefPtr<WebColorPicker> PageClientImpl::createColorPicker(WebPageProxy* page, const WebCore::Color& initialColor,  const WebCore::IntRect& rect)
465{
466    return WebColorPickerMac::create(page, initialColor, rect, wkView());
467}
468#endif
469
470void PageClientImpl::setFindIndicator(PassRefPtr<FindIndicator> findIndicator, bool fadeOut, bool animate)
471{
472    [m_wkView _setFindIndicator:findIndicator fadeOut:fadeOut animate:animate];
473}
474
475void PageClientImpl::accessibilityWebProcessTokenReceived(const IPC::DataReference& data)
476{
477    NSData* remoteToken = [NSData dataWithBytes:data.data() length:data.size()];
478    [m_wkView _setAccessibilityWebProcessToken:remoteToken];
479}
480
481void PageClientImpl::enterAcceleratedCompositingMode(const LayerTreeContext& layerTreeContext)
482{
483    ASSERT(!layerTreeContext.isEmpty());
484
485    CALayer *renderLayer = WKMakeRenderLayer(layerTreeContext.contextID);
486    [m_wkView _setAcceleratedCompositingModeRootLayer:renderLayer];
487}
488
489void PageClientImpl::exitAcceleratedCompositingMode()
490{
491    [m_wkView _setAcceleratedCompositingModeRootLayer:nil];
492}
493
494void PageClientImpl::updateAcceleratedCompositingMode(const LayerTreeContext& layerTreeContext)
495{
496    ASSERT(!layerTreeContext.isEmpty());
497
498    CALayer *renderLayer = WKMakeRenderLayer(layerTreeContext.contextID);
499    [m_wkView _setAcceleratedCompositingModeRootLayer:renderLayer];
500}
501
502void PageClientImpl::setAcceleratedCompositingRootLayer(CALayer *rootLayer)
503{
504    [m_wkView _setAcceleratedCompositingModeRootLayer:rootLayer];
505}
506
507CALayer *PageClientImpl::acceleratedCompositingRootLayer() const
508{
509    return m_wkView._acceleratedCompositingModeRootLayer;
510}
511
512PassRefPtr<ViewSnapshot> PageClientImpl::takeViewSnapshot()
513{
514    return [m_wkView _takeViewSnapshot];
515}
516
517void PageClientImpl::wheelEventWasNotHandledByWebCore(const NativeWebWheelEvent& event)
518{
519    [m_wkView _wheelEventWasNotHandledByWebCore:event.nativeEvent()];
520}
521
522void PageClientImpl::pluginFocusOrWindowFocusChanged(uint64_t pluginComplexTextInputIdentifier, bool pluginHasFocusAndWindowHasFocus)
523{
524    [m_wkView _pluginFocusOrWindowFocusChanged:pluginHasFocusAndWindowHasFocus pluginComplexTextInputIdentifier:pluginComplexTextInputIdentifier];
525}
526
527void PageClientImpl::setPluginComplexTextInputState(uint64_t pluginComplexTextInputIdentifier, PluginComplexTextInputState pluginComplexTextInputState)
528{
529    [m_wkView _setPluginComplexTextInputState:pluginComplexTextInputState pluginComplexTextInputIdentifier:pluginComplexTextInputIdentifier];
530}
531
532void PageClientImpl::didPerformDictionaryLookup(const AttributedString& text, const DictionaryPopupInfo& dictionaryPopupInfo)
533{
534    RetainPtr<NSAttributedString> attributedString = text.string;
535    NSPoint textBaselineOrigin = dictionaryPopupInfo.origin;
536
537    // Convert to screen coordinates.
538    textBaselineOrigin = [m_wkView convertPoint:textBaselineOrigin toView:nil];
539    textBaselineOrigin = [m_wkView.window convertRectToScreen:NSMakeRect(textBaselineOrigin.x, textBaselineOrigin.y, 0, 0)].origin;
540
541    WKShowWordDefinitionWindow(attributedString.get(), textBaselineOrigin, (NSDictionary *)dictionaryPopupInfo.options.get());
542}
543
544void PageClientImpl::dismissDictionaryLookupPanel()
545{
546    // FIXME: We don't know which panel we are dismissing, it may not even be in the current page (see <rdar://problem/13875766>).
547    WKHideWordDefinitionWindow();
548}
549
550void PageClientImpl::showCorrectionPanel(AlternativeTextType type, const FloatRect& boundingBoxOfReplacedString, const String& replacedString, const String& replacementString, const Vector<String>& alternativeReplacementStrings)
551{
552#if USE(AUTOCORRECTION_PANEL)
553    if (!isViewVisible() || !isViewInWindow())
554        return;
555    m_correctionPanel.show(m_wkView, type, boundingBoxOfReplacedString, replacedString, replacementString, alternativeReplacementStrings);
556#endif
557}
558
559void PageClientImpl::dismissCorrectionPanel(ReasonForDismissingAlternativeText reason)
560{
561#if USE(AUTOCORRECTION_PANEL)
562    m_correctionPanel.dismiss(reason);
563#endif
564}
565
566String PageClientImpl::dismissCorrectionPanelSoon(WebCore::ReasonForDismissingAlternativeText reason)
567{
568#if USE(AUTOCORRECTION_PANEL)
569    return m_correctionPanel.dismiss(reason);
570#else
571    return String();
572#endif
573}
574
575void PageClientImpl::recordAutocorrectionResponse(AutocorrectionResponseType responseType, const String& replacedString, const String& replacementString)
576{
577    NSCorrectionResponse response = responseType == AutocorrectionReverted ? NSCorrectionResponseReverted : NSCorrectionResponseEdited;
578    CorrectionPanel::recordAutocorrectionResponse(m_wkView, response, replacedString, replacementString);
579}
580
581void PageClientImpl::recommendedScrollbarStyleDidChange(int32_t newStyle)
582{
583    NSArray *trackingAreas = [m_wkView trackingAreas];
584    NSUInteger count = [trackingAreas count];
585    ASSERT(count == 1);
586
587    for (NSUInteger i = 0; i < count; ++i)
588        [m_wkView removeTrackingArea:[trackingAreas objectAtIndex:i]];
589
590    // Now re-create a tracking area with the appropriate options given the new scrollbar style
591    NSTrackingAreaOptions options = NSTrackingMouseMoved | NSTrackingMouseEnteredAndExited | NSTrackingInVisibleRect;
592    if (newStyle == NSScrollerStyleLegacy)
593        options |= NSTrackingActiveAlways;
594    else
595        options |= NSTrackingActiveInKeyWindow;
596
597    NSTrackingArea *trackingArea = [[NSTrackingArea alloc] initWithRect:[m_wkView frame]
598                                                                options:options
599                                                                  owner:m_wkView
600                                                               userInfo:nil];
601    [m_wkView addTrackingArea:trackingArea];
602    [trackingArea release];
603}
604
605void PageClientImpl::intrinsicContentSizeDidChange(const IntSize& intrinsicContentSize)
606{
607    [m_wkView _setIntrinsicContentSize:intrinsicContentSize];
608}
609
610bool PageClientImpl::executeSavedCommandBySelector(const String& selectorString)
611{
612    return [m_wkView _executeSavedCommandBySelector:NSSelectorFromString(selectorString)];
613}
614
615#if USE(DICTATION_ALTERNATIVES)
616uint64_t PageClientImpl::addDictationAlternatives(const RetainPtr<NSTextAlternatives>& alternatives)
617{
618    return m_alternativeTextUIController->addAlternatives(alternatives);
619}
620
621void PageClientImpl::removeDictationAlternatives(uint64_t dictationContext)
622{
623    m_alternativeTextUIController->removeAlternatives(dictationContext);
624}
625
626void PageClientImpl::showDictationAlternativeUI(const WebCore::FloatRect& boundingBoxOfDictatedText, uint64_t dictationContext)
627{
628    if (!isViewVisible() || !isViewInWindow())
629        return;
630    m_alternativeTextUIController->showAlternatives(m_wkView, boundingBoxOfDictatedText, dictationContext, ^(NSString* acceptedAlternative){
631        [m_wkView handleAcceptedAlternativeText:acceptedAlternative];
632    });
633}
634
635Vector<String> PageClientImpl::dictationAlternatives(uint64_t dictationContext)
636{
637    return m_alternativeTextUIController->alternativesForContext(dictationContext);
638}
639#endif
640
641#if ENABLE(FULLSCREEN_API)
642
643WebFullScreenManagerProxyClient& PageClientImpl::fullScreenManagerProxyClient()
644{
645    return *this;
646}
647
648// WebFullScreenManagerProxyClient
649
650void PageClientImpl::closeFullScreenManager()
651{
652    [m_wkView _closeFullScreenWindowController];
653}
654
655bool PageClientImpl::isFullScreen()
656{
657    if (!m_wkView._hasFullScreenWindowController)
658        return false;
659
660    return m_wkView._fullScreenWindowController.isFullScreen;
661}
662
663void PageClientImpl::enterFullScreen()
664{
665    [m_wkView._fullScreenWindowController enterFullScreen:nil];
666}
667
668void PageClientImpl::exitFullScreen()
669{
670    [m_wkView._fullScreenWindowController exitFullScreen];
671}
672
673void PageClientImpl::beganEnterFullScreen(const IntRect& initialFrame, const IntRect& finalFrame)
674{
675    [m_wkView._fullScreenWindowController beganEnterFullScreenWithInitialFrame:initialFrame finalFrame:finalFrame];
676}
677
678void PageClientImpl::beganExitFullScreen(const IntRect& initialFrame, const IntRect& finalFrame)
679{
680    [m_wkView._fullScreenWindowController beganExitFullScreenWithInitialFrame:initialFrame finalFrame:finalFrame];
681}
682
683#endif // ENABLE(FULLSCREEN_API)
684
685void PageClientImpl::navigationGestureDidBegin()
686{
687#if WK_API_ENABLED
688    if (m_webView)
689        NavigationState::fromWebPage(*m_webView->_page).navigationGestureDidBegin();
690#endif
691}
692
693void PageClientImpl::navigationGestureWillEnd(bool willNavigate, WebBackForwardListItem& item)
694{
695#if WK_API_ENABLED
696    if (m_webView)
697        NavigationState::fromWebPage(*m_webView->_page).navigationGestureWillEnd(willNavigate, item);
698#else
699    UNUSED_PARAM(willNavigate);
700    UNUSED_PARAM(item);
701#endif
702}
703
704void PageClientImpl::navigationGestureDidEnd(bool willNavigate, WebBackForwardListItem& item)
705{
706#if WK_API_ENABLED
707    if (m_webView)
708        NavigationState::fromWebPage(*m_webView->_page).navigationGestureDidEnd(willNavigate, item);
709#else
710    UNUSED_PARAM(willNavigate);
711    UNUSED_PARAM(item);
712#endif
713}
714
715void PageClientImpl::willRecordNavigationSnapshot(WebBackForwardListItem& item)
716{
717#if WK_API_ENABLED
718    if (m_webView)
719        NavigationState::fromWebPage(*m_webView->_page).willRecordNavigationSnapshot(item);
720#else
721    UNUSED_PARAM(item);
722#endif
723}
724
725void PageClientImpl::didFirstVisuallyNonEmptyLayoutForMainFrame()
726{
727    [m_wkView _didFirstVisuallyNonEmptyLayoutForMainFrame];
728}
729
730void PageClientImpl::didFinishLoadForMainFrame()
731{
732    [m_wkView _didFinishLoadForMainFrame];
733}
734
735void PageClientImpl::didSameDocumentNavigationForMainFrame(SameDocumentNavigationType type)
736{
737    [m_wkView _didSameDocumentNavigationForMainFrame:type];
738}
739
740void PageClientImpl::removeNavigationGestureSnapshot()
741{
742    [m_wkView _removeNavigationGestureSnapshot];
743}
744
745CGRect PageClientImpl::boundsOfLayerInLayerBackedWindowCoordinates(CALayer *layer) const
746{
747    CALayer *windowContentLayer = static_cast<NSView *>(m_wkView.window.contentView).layer;
748    ASSERT(windowContentLayer);
749
750    return [windowContentLayer convertRect:layer.bounds fromLayer:layer];
751}
752
753} // namespace WebKit
754
755#endif // PLATFORM(MAC)
756