8d5f167d67fe61d0829dec65dbfa9229113cba70
[WebKit-https.git] / Source / WebKit2 / UIProcess / API / ios / WKContentView.mm
1 /*
2  * Copyright (C) 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 "WKContentViewInternal.h"
28
29 #import "PageClientImplIOS.h"
30 #import "RemoteLayerTreeDrawingAreaProxy.h"
31 #import "TiledCoreAnimationDrawingAreaProxyIOS.h"
32 #import "UIWKRemoteView.h"
33 #import "WKBrowsingContextControllerInternal.h"
34 #import "WKBrowsingContextGroupPrivate.h"
35 #import "WKGeolocationProviderIOS.h"
36 #import "WKProcessGroupPrivate.h"
37 #import "WKInteractionView.h"
38 #import "WebContext.h"
39 #import "WebPageGroup.h"
40 #import "WebSystemInterface.h"
41 #import <QuartzCore/CALayerHost.h>
42 #import <UIKit/UIWindow_Private.h>
43 #import <WebCore/ViewportArguments.h>
44 #import <WebCore/WebCoreThreadSystemInterface.h>
45 #import <wtf/RetainPtr.h>
46
47 using namespace WebCore;
48 using namespace WebKit;
49
50 @interface WKContentView (Internal) <WKBrowsingContextLoadDelegateInternal>
51 @end
52
53 @implementation WKContentView {
54     RetainPtr<WKProcessGroup> _processGroup;
55     RetainPtr<WKBrowsingContextGroup> _browsingContextGroup;
56     OwnPtr<PageClientImpl> _pageClient;
57     RefPtr<WebPageProxy> _page;
58
59     RetainPtr<WKBrowsingContextController> _browsingContextController;
60
61     RetainPtr<UIView> _rootContentView;
62     RetainPtr<WKInteractionView> _interactionView;
63 }
64
65 - (id)initWithCoder:(NSCoder *)coder
66 {
67     if (!(self = [super initWithCoder:coder]))
68         return nil;
69
70     [self _commonInitWithProcessGroup:nil browsingContextGroup:nil];
71     return self;
72 }
73
74 - (id)initWithFrame:(CGRect)frame
75 {
76     return [self initWithFrame:frame processGroup:nil browsingContextGroup:nil];
77 }
78
79 - (id)initWithFrame:(CGRect)frame processGroup:(WKProcessGroup *)processGroup browsingContextGroup:(WKBrowsingContextGroup *)browsingContextGroup
80 {
81     if (!(self = [super initWithFrame:frame]))
82         return nil;
83
84     [self _commonInitWithProcessGroup:processGroup browsingContextGroup:browsingContextGroup];
85     return self;
86 }
87
88 - (void)dealloc
89 {
90     _page->close();
91
92     WebContext::statistics().wkViewCount--;
93
94     [super dealloc];
95 }
96
97 - (void)willMoveToWindow:(UIWindow *)newWindow
98 {
99     NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
100     UIWindow *window = self.window;
101
102     if (window)
103         [defaultCenter removeObserver:self name:UIWindowDidMoveToScreenNotification object:window];
104
105     if (newWindow)
106         [defaultCenter addObserver:self selector:@selector(_windowDidMoveToScreenNotification:) name:UIWindowDidMoveToScreenNotification object:newWindow];
107 }
108
109 - (void)didMoveToWindow
110 {
111     if (self.window)
112         [self _updateForScreen:self.window.screen];
113     _page->viewStateDidChange(ViewState::IsInWindow);
114 }
115
116 - (WKBrowsingContextController *)browsingContextController
117 {
118     return _browsingContextController.get();
119 }
120
121 - (WKContentType)contentType
122 {
123     if (_page->mainFrame()->mimeType() == "text/plain")
124         return WKContentType::PlainText;
125     else if (_page->mainFrame()->isDisplayingStandaloneImageDocument())
126         return WKContentType::Image;
127     return WKContentType::Standard;
128 }
129
130 - (void)setMinimumSize:(CGSize)size
131 {
132     _page->drawingArea()->setSize(IntSize(size), IntSize(), IntSize());
133 }
134
135 - (void)setViewportSize:(CGSize)size
136 {
137     _page->setFixedLayoutSize(IntSize(size));
138 }
139
140 - (void)didScrollTo:(CGPoint)contentOffset
141 {
142     _page->didFinishScrolling(contentOffset);
143 }
144
145 - (void)didZoomToScale:(CGFloat)scale
146 {
147     _page->didFinishZooming(scale);
148 }
149
150 static void decidePolicyForGeolocationPermissionRequest(WKPageRef page, WKFrameRef frame, WKSecurityOriginRef origin, WKGeolocationPermissionRequestRef permissionRequest, const void* clientInfo)
151 {
152     WKContentView *view = reinterpret_cast<WKContentView *>(const_cast<void*>(clientInfo));
153     ASSERT([view isKindOfClass:[WKContentView class]]);
154
155     [[view->_processGroup _geolocationProvider] decidePolicyForGeolocationRequestFromOrigin:origin frame:frame request:permissionRequest window:[view window]];
156 }
157
158 - (void)_commonInitWithProcessGroup:(WKProcessGroup *)processGroup browsingContextGroup:(WKBrowsingContextGroup *)browsingContextGroup
159 {
160     // FIXME: This should not be necessary, find why hit testing does not work otherwise.
161     // <rdar://problem/12287363>
162     self.backgroundColor = [UIColor blackColor];
163
164     InitWebCoreThreadSystemInterface();
165     InitWebCoreSystemInterface();
166     RunLoop::initializeMainRunLoop();
167
168     _processGroup = processGroup ? processGroup : adoptNS([[WKProcessGroup alloc] init]);
169     _browsingContextGroup = browsingContextGroup ? browsingContextGroup : adoptNS([[WKBrowsingContextGroup alloc] initWithIdentifier:nil]);
170     _pageClient = PageClientImpl::create(self);
171     WebContext* processContext = toImpl([_processGroup _contextRef]);
172     _page = processContext->createWebPage(_pageClient.get(), toImpl([_browsingContextGroup _pageGroupRef]));
173     _page->initializeWebPage();
174     _page->setIntrinsicDeviceScaleFactor([UIScreen mainScreen].scale);
175     _page->setUseFixedLayout(true);
176
177     WKPageUIClient pageUIClient = {
178         kWKPageUIClientCurrentVersion,
179         self,
180         0, // createNewPage_deprecatedForUseWithV0
181         0, // showPage
182         0, // closeOtherPage
183         0, // takeFocus
184         0, // focus
185         0, // unfocus
186         0, // runJavaScriptAlert
187         0, // runJavaScriptConfirm
188         0, // runJavaScriptPrompt
189         0, // setStatusText
190         0, // mouseDidMoveOverElement_deprecatedForUseWithV0
191         0, // missingPluginButtonClicked
192         0, // didNotHandleKeyEvent
193         0, // didNotHandleWheelEvent
194         0, // toolbarsAreVisible
195         0, // setToolbarsAreVisible
196         0, // menuBarIsVisible
197         0, // setMenuBarIsVisible
198         0, // statusBarIsVisible
199         0, // setStatusBarIsVisible
200         0, // isResizable
201         0, // setIsResizable
202         0, // getWindowFrameOtherPage
203         0, // setWindowFrameOtherPage
204         0, // runBeforeUnloadConfirmPanel
205         0, // didDraw
206         0, // pageDidScroll
207         0, // exceededDatabaseQuota
208         0, // runOpenPanel
209         decidePolicyForGeolocationPermissionRequest,
210         0, // headerHeight
211         0, // footerHeight
212         0, // drawHeader
213         0, // drawFooter
214         0, // printFrame
215         0, // runModal
216         0, // didCompleteRubberBandForMainFrame
217         0, // saveDataToFileInDownloadsFolder
218         0, // shouldInterruptJavaScript
219         0, // createOtherPage
220         0, // mouseDidMoveOverElement
221         0, // decidePolicyForNotificationPermissionRequest
222         0, // unavailablePluginButtonClicked
223         0, // showColorPicker
224         0, // hideColorPicker
225         0, // unavailablePluginButtonClicked
226     };
227     WKPageSetPageUIClient(toAPI(_page.get()), &pageUIClient);
228
229     _browsingContextController = adoptNS([[WKBrowsingContextController alloc] _initWithPageRef:toAPI(_page.get())]);
230     [_browsingContextController setLoadDelegateInternal:self];
231
232     WebContext::statistics().wkViewCount++;
233
234     _rootContentView = adoptNS([[UIView alloc] init]);
235     [[_rootContentView layer] setMasksToBounds:NO];
236     [_rootContentView setUserInteractionEnabled:NO];
237
238     [self addSubview:_rootContentView.get()];
239
240     _interactionView = adoptNS([[WKInteractionView alloc] init]);
241     [_interactionView setPage:_page];
242     [self addSubview:_interactionView.get()];
243 }
244
245 - (void)_windowDidMoveToScreenNotification:(NSNotification *)notification
246 {
247     ASSERT(notification.object == self.window);
248
249     UIScreen *screen = notification.userInfo[UIWindowNewScreenUserInfoKey];
250     [self _updateForScreen:screen];
251 }
252
253 - (void)_updateForScreen:(UIScreen *)screen
254 {
255     ASSERT(screen);
256     _page->setIntrinsicDeviceScaleFactor(screen.scale);
257 }
258
259 - (void)_didChangeViewportArguments:(const WebCore::ViewportArguments&)arguments
260 {
261     if ([_delegate respondsToSelector:@selector(contentView:didChangeViewportArgumentsSize:initialScale:minimumScale:maximumScale:allowsUserScaling:)])
262         [_delegate contentView:self
263 didChangeViewportArgumentsSize:CGSizeMake(arguments.width, arguments.height)
264                   initialScale:arguments.zoom
265                   minimumScale:arguments.minZoom
266                   maximumScale:arguments.maxZoom
267              allowsUserScaling:arguments.userZoom];
268 }
269
270 #pragma mark PageClientImpl methods
271
272 - (std::unique_ptr<DrawingAreaProxy>)_createDrawingAreaProxy
273 {
274     return std::make_unique<RemoteLayerTreeDrawingAreaProxy>(_page.get());
275 }
276
277 - (void)_processDidCrash
278 {
279     // FIXME: Implement.
280 }
281
282 - (void)_didRelaunchProcess
283 {
284     // FIXME: Implement.
285 }
286
287 - (void)browsingContextControllerDidCommitLoad:(WKBrowsingContextController *)sender
288 {
289     ASSERT(sender == _browsingContextController);
290     if ([_delegate respondsToSelector:@selector(contentViewdidCommitLoadForMainFrame:)])
291         [_delegate contentViewdidCommitLoadForMainFrame:self];
292 }
293
294 - (void)_didChangeContentSize:(CGSize)contentsSize
295 {
296     [self setBounds:{CGPointZero, contentsSize}];
297     [_interactionView setFrame:CGRectMake(0, 0, contentsSize.width, contentsSize.height)];
298     [_rootContentView setFrame:CGRectMake(0, 0, contentsSize.width, contentsSize.height)];
299
300     if ([_delegate respondsToSelector:@selector(contentView:contentsSizeDidChange:)])
301         [_delegate contentView:self contentsSizeDidChange:contentsSize];
302 }
303
304 - (void)_mainDocumentDidReceiveMobileDocType
305 {
306     if ([_delegate respondsToSelector:@selector(contentViewDidReceiveMobileDocType:)])
307         [_delegate contentViewDidReceiveMobileDocType:self];
308
309 }
310
311 - (void)_didGetTapHighlightForRequest:(uint64_t)requestID color:(const Color&)color quads:(const Vector<FloatQuad>&)highlightedQuads topLeftRadius:(const IntSize&)topLeftRadius topRightRadius:(const IntSize&)topRightRadius bottomLeftRadius:(const IntSize&)bottomLeftRadius bottomRightRadius:(const IntSize&)bottomRightRadius
312 {
313     [_interactionView _didGetTapHighlightForRequest:requestID color:color quads:highlightedQuads topLeftRadius:topLeftRadius topRightRadius:topRightRadius bottomLeftRadius:bottomLeftRadius bottomRightRadius:bottomRightRadius];
314 }
315
316 - (void)_setAcceleratedCompositingRootLayer:(CALayer *)rootLayer
317 {
318     [[_rootContentView layer] setSublayers:@[rootLayer]];
319 }
320
321 // FIXME: change the name. Leave it for now to make it easier to refer to the UIKit implementation.
322 - (void)_startAssistingNode
323 {
324     [_interactionView _startAssistingNode];
325 }
326
327 - (void)_stopAssistingNode
328 {
329     [_interactionView _stopAssistingNode];
330 }
331
332 - (void)_selectionChanged
333 {
334     [_interactionView _selectionChanged];
335 }
336
337 - (BOOL)_interpretKeyEvent:(WebIOSEvent *)theEvent isCharEvent:(BOOL)isCharEvent
338 {
339     return [_interactionView _interpretKeyEvent:theEvent isCharEvent:isCharEvent];
340 }
341
342 @end