Unify most of the WebKit Objective-C API sources
[WebKit-https.git] / Source / WebKit / WebProcess / InjectedBundle / API / mac / WKWebProcessPlugInBrowserContextController.mm
1 /*
2  * Copyright (C) 2012 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 "WKWebProcessPlugInBrowserContextControllerInternal.h"
28
29 #if WK_API_ENABLED
30
31 #import "APIData.h"
32 #import "RemoteObjectRegistry.h"
33 #import "RemoteObjectRegistryMessages.h"
34 #import "WKBrowsingContextHandleInternal.h"
35 #import "WKBundleAPICast.h"
36 #import "WKBundlePage.h"
37 #import "WKBundlePagePrivate.h"
38 #import "WKDOMInternals.h"
39 #import "WKNSDictionary.h"
40 #import "WKNSError.h"
41 #import "WKNSString.h"
42 #import "WKNSURL.h"
43 #import "WKNSURLRequest.h"
44 #import "WKRetainPtr.h"
45 #import "WKStringCF.h"
46 #import "WKURLRequestNS.h"
47 #import "WKWebProcessPlugInEditingDelegate.h"
48 #import "WKWebProcessPlugInFrameInternal.h"
49 #import "WKWebProcessPlugInInternal.h"
50 #import "WKWebProcessPlugInFormDelegatePrivate.h"
51 #import "WKWebProcessPlugInLoadDelegate.h"
52 #import "WKWebProcessPlugInNodeHandleInternal.h"
53 #import "WKWebProcessPlugInPageGroupInternal.h"
54 #import "WKWebProcessPlugInRangeHandleInternal.h"
55 #import "WKWebProcessPlugInScriptWorldInternal.h"
56 #import "WebPage.h"
57 #import "WebProcess.h"
58 #import "_WKRemoteObjectRegistryInternal.h"
59 #import "_WKRenderingProgressEventsInternal.h"
60 #import "_WKSameDocumentNavigationTypeInternal.h"
61 #import <WebCore/Document.h>
62 #import <WebCore/DocumentFragment.h>
63 #import <WebCore/Frame.h>
64 #import <WebCore/HTMLFormElement.h>
65 #import <WebCore/HTMLInputElement.h>
66 #import <pal/spi/cocoa/NSKeyedArchiverSPI.h>
67 #import <wtf/WeakObjCPtr.h>
68
69 @interface NSObject (WKDeprecatedDelegateMethods)
70 - (void)webProcessPlugInBrowserContextController:(WKWebProcessPlugInBrowserContextController *)controller didSameDocumentNavigationForFrame:(WKWebProcessPlugInFrame *)frame;
71 @end
72
73 @implementation WKWebProcessPlugInBrowserContextController {
74     API::ObjectStorage<WebKit::WebPage> _page;
75     WeakObjCPtr<id <WKWebProcessPlugInLoadDelegate>> _loadDelegate;
76     WeakObjCPtr<id <WKWebProcessPlugInFormDelegatePrivate>> _formDelegate;
77     WeakObjCPtr<id <WKWebProcessPlugInEditingDelegate>> _editingDelegate;
78     
79     RetainPtr<_WKRemoteObjectRegistry> _remoteObjectRegistry;
80 }
81
82 static void didStartProvisionalLoadForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef* userDataRef, const void *clientInfo)
83 {
84     auto pluginContextController = (__bridge WKWebProcessPlugInBrowserContextController *)clientInfo;
85     auto loadDelegate = pluginContextController->_loadDelegate.get();
86
87     if ([loadDelegate respondsToSelector:@selector(webProcessPlugInBrowserContextController:didStartProvisionalLoadForFrame:)])
88         [loadDelegate webProcessPlugInBrowserContextController:pluginContextController didStartProvisionalLoadForFrame:wrapper(*WebKit::toImpl(frame))];
89 }
90
91 static void didReceiveServerRedirectForProvisionalLoadForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef *userDataRef, const void *clientInfo)
92 {
93     auto pluginContextController = (__bridge WKWebProcessPlugInBrowserContextController *)clientInfo;
94     auto loadDelegate = pluginContextController->_loadDelegate.get();
95
96     if ([loadDelegate respondsToSelector:@selector(webProcessPlugInBrowserContextController:didReceiveServerRedirectForProvisionalLoadForFrame:)])
97         [loadDelegate webProcessPlugInBrowserContextController:pluginContextController didReceiveServerRedirectForProvisionalLoadForFrame:wrapper(*WebKit::toImpl(frame))];
98 }
99
100 static void didFinishLoadForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef* userData, const void *clientInfo)
101 {
102     auto pluginContextController = (__bridge WKWebProcessPlugInBrowserContextController *)clientInfo;
103     auto loadDelegate = pluginContextController->_loadDelegate.get();
104
105     if ([loadDelegate respondsToSelector:@selector(webProcessPlugInBrowserContextController:didFinishLoadForFrame:)])
106         [loadDelegate webProcessPlugInBrowserContextController:pluginContextController didFinishLoadForFrame:wrapper(*WebKit::toImpl(frame))];
107 }
108
109 static void globalObjectIsAvailableForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKBundleScriptWorldRef scriptWorld, const void* clientInfo)
110 {
111     auto pluginContextController = (__bridge WKWebProcessPlugInBrowserContextController *)clientInfo;
112     auto loadDelegate = pluginContextController->_loadDelegate.get();
113
114     if ([loadDelegate respondsToSelector:@selector(webProcessPlugInBrowserContextController:globalObjectIsAvailableForFrame:inScriptWorld:)])
115         [loadDelegate webProcessPlugInBrowserContextController:pluginContextController globalObjectIsAvailableForFrame:wrapper(*WebKit::toImpl(frame)) inScriptWorld:wrapper(*WebKit::toImpl(scriptWorld))];
116 }
117
118 static void didRemoveFrameFromHierarchy(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef* userData, const void* clientInfo)
119 {
120     auto pluginContextController = (__bridge WKWebProcessPlugInBrowserContextController *)clientInfo;
121     auto loadDelegate = pluginContextController->_loadDelegate.get();
122
123     if ([loadDelegate respondsToSelector:@selector(webProcessPlugInBrowserContextController:didRemoveFrameFromHierarchy:)])
124         [loadDelegate webProcessPlugInBrowserContextController:pluginContextController didRemoveFrameFromHierarchy:wrapper(*WebKit::toImpl(frame))];
125 }
126
127 static void didCommitLoadForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef* userData, const void *clientInfo)
128 {
129     auto pluginContextController = (__bridge WKWebProcessPlugInBrowserContextController *)clientInfo;
130     auto loadDelegate = pluginContextController->_loadDelegate.get();
131
132     if ([loadDelegate respondsToSelector:@selector(webProcessPlugInBrowserContextController:didCommitLoadForFrame:)])
133         [loadDelegate webProcessPlugInBrowserContextController:pluginContextController didCommitLoadForFrame:wrapper(*WebKit::toImpl(frame))];
134 }
135
136 static void didFinishDocumentLoadForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef* userData, const void *clientInfo)
137 {
138     auto pluginContextController = (__bridge WKWebProcessPlugInBrowserContextController *)clientInfo;
139     auto loadDelegate = pluginContextController->_loadDelegate.get();
140
141     if ([loadDelegate respondsToSelector:@selector(webProcessPlugInBrowserContextController:didFinishDocumentLoadForFrame:)])
142         [loadDelegate webProcessPlugInBrowserContextController:pluginContextController didFinishDocumentLoadForFrame:wrapper(*WebKit::toImpl(frame))];
143 }
144
145 static void didFailProvisionalLoadWithErrorForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKErrorRef wkError, WKTypeRef* userData, const void *clientInfo)
146 {
147     auto pluginContextController = (__bridge WKWebProcessPlugInBrowserContextController *)clientInfo;
148     auto loadDelegate = pluginContextController->_loadDelegate.get();
149
150     if ([loadDelegate respondsToSelector:@selector(webProcessPlugInBrowserContextController:didFailProvisionalLoadWithErrorForFrame:error:)])
151         [loadDelegate webProcessPlugInBrowserContextController:pluginContextController didFailProvisionalLoadWithErrorForFrame:wrapper(*WebKit::toImpl(frame)) error:wrapper(*WebKit::toImpl(wkError))];
152 }
153
154 static void didFailLoadWithErrorForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKErrorRef wkError, WKTypeRef* userData, const void *clientInfo)
155 {
156     auto pluginContextController = (__bridge WKWebProcessPlugInBrowserContextController *)clientInfo;
157     auto loadDelegate = pluginContextController->_loadDelegate.get();
158
159     if ([loadDelegate respondsToSelector:@selector(webProcessPlugInBrowserContextController:didFailLoadWithErrorForFrame:error:)])
160         [loadDelegate webProcessPlugInBrowserContextController:pluginContextController didFailLoadWithErrorForFrame:wrapper(*WebKit::toImpl(frame)) error:wrapper(*WebKit::toImpl(wkError))];
161 }
162
163 static void didSameDocumentNavigationForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKSameDocumentNavigationType type, WKTypeRef* userData, const void *clientInfo)
164 {
165     auto pluginContextController = (__bridge WKWebProcessPlugInBrowserContextController *)clientInfo;
166     auto loadDelegate = pluginContextController->_loadDelegate.get();
167
168     if ([loadDelegate respondsToSelector:@selector(webProcessPlugInBrowserContextController:didSameDocumentNavigation:forFrame:)])
169         [loadDelegate webProcessPlugInBrowserContextController:pluginContextController didSameDocumentNavigation:toWKSameDocumentNavigationType(WebKit::toSameDocumentNavigationType(type)) forFrame:wrapper(*WebKit::toImpl(frame))];
170     else {
171         // FIXME: Remove this once clients switch to implementing the above delegate method.
172         if ([loadDelegate respondsToSelector:@selector(webProcessPlugInBrowserContextController:didSameDocumentNavigationForFrame:)])
173             [(NSObject *)loadDelegate webProcessPlugInBrowserContextController:pluginContextController didSameDocumentNavigationForFrame:wrapper(*WebKit::toImpl(frame))];
174     }
175 }
176
177 static void didLayoutForFrame(WKBundlePageRef page, WKBundleFrameRef frame, const void* clientInfo)
178 {
179     auto pluginContextController = (__bridge WKWebProcessPlugInBrowserContextController *)clientInfo;
180     auto loadDelegate = pluginContextController->_loadDelegate.get();
181
182     if ([loadDelegate respondsToSelector:@selector(webProcessPlugInBrowserContextController:didLayoutForFrame:)])
183         [loadDelegate webProcessPlugInBrowserContextController:pluginContextController didLayoutForFrame:wrapper(*WebKit::toImpl(frame))];
184 }
185
186 static void didReachLayoutMilestone(WKBundlePageRef page, WKLayoutMilestones milestones, WKTypeRef* userData, const void *clientInfo)
187 {
188     auto pluginContextController = (__bridge WKWebProcessPlugInBrowserContextController *)clientInfo;
189     auto loadDelegate = pluginContextController->_loadDelegate.get();
190
191     if ([loadDelegate respondsToSelector:@selector(webProcessPlugInBrowserContextController:renderingProgressDidChange:)])
192         [loadDelegate webProcessPlugInBrowserContextController:pluginContextController renderingProgressDidChange:renderingProgressEvents(WebKit::toLayoutMilestones(milestones))];
193 }
194
195 static void didFirstVisuallyNonEmptyLayoutForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef* userData, const void *clientInfo)
196 {
197     auto pluginContextController = (__bridge WKWebProcessPlugInBrowserContextController *)clientInfo;
198     auto loadDelegate = pluginContextController->_loadDelegate.get();
199
200     if ([loadDelegate respondsToSelector:@selector(webProcessPlugInBrowserContextController:didFirstVisuallyNonEmptyLayoutForFrame:)])
201         [loadDelegate webProcessPlugInBrowserContextController:pluginContextController didFirstVisuallyNonEmptyLayoutForFrame:wrapper(*WebKit::toImpl(frame))];
202 }
203
204 static void didHandleOnloadEventsForFrame(WKBundlePageRef page, WKBundleFrameRef frame, const void* clientInfo)
205 {
206     auto pluginContextController = (__bridge WKWebProcessPlugInBrowserContextController *)clientInfo;
207     auto loadDelegate = pluginContextController->_loadDelegate.get();
208
209     if ([loadDelegate respondsToSelector:@selector(webProcessPlugInBrowserContextController:didHandleOnloadEventsForFrame:)])
210         [loadDelegate webProcessPlugInBrowserContextController:pluginContextController didHandleOnloadEventsForFrame:wrapper(*WebKit::toImpl(frame))];
211 }
212
213 static WKStringRef userAgentForURL(WKBundleFrameRef frame, WKURLRef url, const void* clientInfo)
214 {
215     auto pluginContextController = (__bridge WKWebProcessPlugInBrowserContextController *)clientInfo;
216     auto loadDelegate = pluginContextController->_loadDelegate.get();
217     
218     if ([loadDelegate respondsToSelector:@selector(webProcessPlugInBrowserContextController:frame:userAgentForURL:)]) {
219         WKWebProcessPlugInFrame *newFrame = wrapper(*WebKit::toImpl(frame));
220         NSString *string = [loadDelegate webProcessPlugInBrowserContextController:pluginContextController frame:newFrame userAgentForURL:wrapper(*WebKit::toImpl(url))];
221         if (!string)
222             return nullptr;
223
224         return WKStringCreateWithCFString((__bridge CFStringRef)string);
225     }
226     
227     return nullptr;
228 }
229
230 static void setUpPageLoaderClient(WKWebProcessPlugInBrowserContextController *contextController, WebKit::WebPage& page)
231 {
232     WKBundlePageLoaderClientV9 client;
233     memset(&client, 0, sizeof(client));
234
235     client.base.version = 8;
236     client.base.clientInfo = (__bridge void*)contextController;
237     client.didStartProvisionalLoadForFrame = didStartProvisionalLoadForFrame;
238     client.didReceiveServerRedirectForProvisionalLoadForFrame = didReceiveServerRedirectForProvisionalLoadForFrame;
239     client.didCommitLoadForFrame = didCommitLoadForFrame;
240     client.didFinishDocumentLoadForFrame = didFinishDocumentLoadForFrame;
241     client.didFailProvisionalLoadWithErrorForFrame = didFailProvisionalLoadWithErrorForFrame;
242     client.didFailLoadWithErrorForFrame = didFailLoadWithErrorForFrame;
243     client.didSameDocumentNavigationForFrame = didSameDocumentNavigationForFrame;
244     client.didFinishLoadForFrame = didFinishLoadForFrame;
245     client.globalObjectIsAvailableForFrame = globalObjectIsAvailableForFrame;
246     client.didRemoveFrameFromHierarchy = didRemoveFrameFromHierarchy;
247     client.didHandleOnloadEventsForFrame = didHandleOnloadEventsForFrame;
248     client.didFirstVisuallyNonEmptyLayoutForFrame = didFirstVisuallyNonEmptyLayoutForFrame;
249     client.userAgentForURL = userAgentForURL;
250
251     client.didLayoutForFrame = didLayoutForFrame;
252     client.didLayout = didReachLayoutMilestone;
253
254     WKBundlePageSetPageLoaderClient(toAPI(&page), &client.base);
255 }
256
257 static WKURLRequestRef willSendRequestForFrame(WKBundlePageRef, WKBundleFrameRef frame, uint64_t resourceIdentifier, WKURLRequestRef request, WKURLResponseRef redirectResponse, const void* clientInfo)
258 {
259     auto pluginContextController = (__bridge WKWebProcessPlugInBrowserContextController *)clientInfo;
260     auto loadDelegate = pluginContextController->_loadDelegate.get();
261
262     if ([loadDelegate respondsToSelector:@selector(webProcessPlugInBrowserContextController:frame:willSendRequestForResource:request:redirectResponse:)]) {
263         NSURLRequest *originalRequest = wrapper(*WebKit::toImpl(request));
264         RetainPtr<NSURLRequest> substituteRequest = [loadDelegate webProcessPlugInBrowserContextController:pluginContextController frame:wrapper(*WebKit::toImpl(frame)) willSendRequestForResource:resourceIdentifier
265             request:originalRequest redirectResponse:WebKit::toImpl(redirectResponse)->resourceResponse().nsURLResponse()];
266
267         if (substituteRequest != originalRequest)
268             return substituteRequest ? WKURLRequestCreateWithNSURLRequest(substituteRequest.get()) : nullptr;
269     } else if ([loadDelegate respondsToSelector:@selector(webProcessPlugInBrowserContextController:frame:willSendRequest:redirectResponse:)]) {
270         NSURLRequest *originalRequest = wrapper(*WebKit::toImpl(request));
271         RetainPtr<NSURLRequest> substituteRequest = [loadDelegate webProcessPlugInBrowserContextController:pluginContextController frame:wrapper(*WebKit::toImpl(frame)) willSendRequest:originalRequest
272             redirectResponse:WebKit::toImpl(redirectResponse)->resourceResponse().nsURLResponse()];
273
274         if (substituteRequest != originalRequest)
275             return substituteRequest ? WKURLRequestCreateWithNSURLRequest(substituteRequest.get()) : nullptr;
276     }
277
278     WKRetain(request);
279     return request;
280 }
281
282 static void didInitiateLoadForResource(WKBundlePageRef, WKBundleFrameRef frame, uint64_t resourceIdentifier, WKURLRequestRef request, bool pageIsProvisionallyLoading, const void* clientInfo)
283 {
284     auto pluginContextController = (__bridge WKWebProcessPlugInBrowserContextController *)clientInfo;
285     auto loadDelegate = pluginContextController->_loadDelegate.get();
286
287     if ([loadDelegate respondsToSelector:@selector(webProcessPlugInBrowserContextController:frame:didInitiateLoadForResource:request:pageIsProvisionallyLoading:)]) {
288         [loadDelegate webProcessPlugInBrowserContextController:pluginContextController frame:wrapper(*WebKit::toImpl(frame)) didInitiateLoadForResource:resourceIdentifier request:wrapper(*WebKit::toImpl(request))
289             pageIsProvisionallyLoading:pageIsProvisionallyLoading];
290     } else if ([loadDelegate respondsToSelector:@selector(webProcessPlugInBrowserContextController:frame:didInitiateLoadForResource:request:)]) {
291         [loadDelegate webProcessPlugInBrowserContextController:pluginContextController frame:wrapper(*WebKit::toImpl(frame)) didInitiateLoadForResource:resourceIdentifier request:wrapper(*WebKit::toImpl(request))];
292     }
293 }
294
295 static void didFinishLoadForResource(WKBundlePageRef, WKBundleFrameRef frame, uint64_t resourceIdentifier, const void* clientInfo)
296 {
297     auto pluginContextController = (__bridge WKWebProcessPlugInBrowserContextController *)clientInfo;
298     auto loadDelegate = pluginContextController->_loadDelegate.get();
299
300     if ([loadDelegate respondsToSelector:@selector(webProcessPlugInBrowserContextController:frame:didFinishLoadForResource:)]) {
301         [loadDelegate webProcessPlugInBrowserContextController:pluginContextController frame:wrapper(*WebKit::toImpl(frame)) didFinishLoadForResource:resourceIdentifier];
302     }
303 }
304
305 static void didFailLoadForResource(WKBundlePageRef, WKBundleFrameRef frame, uint64_t resourceIdentifier, WKErrorRef error, const void* clientInfo)
306 {
307     auto pluginContextController = (__bridge WKWebProcessPlugInBrowserContextController *)clientInfo;
308     auto loadDelegate = pluginContextController->_loadDelegate.get();
309
310     if ([loadDelegate respondsToSelector:@selector(webProcessPlugInBrowserContextController:frame:didFailLoadForResource:error:)]) {
311         [loadDelegate webProcessPlugInBrowserContextController:pluginContextController frame:wrapper(*WebKit::toImpl(frame)) didFailLoadForResource:resourceIdentifier error:wrapper(*WebKit::toImpl(error))];
312     }
313 }
314
315 static void setUpResourceLoadClient(WKWebProcessPlugInBrowserContextController *contextController, WebKit::WebPage& page)
316 {
317     WKBundlePageResourceLoadClientV1 client;
318     memset(&client, 0, sizeof(client));
319
320     client.base.version = 1;
321     client.base.clientInfo = (__bridge void*) contextController;
322     client.willSendRequestForFrame = willSendRequestForFrame;
323     client.didInitiateLoadForResource = didInitiateLoadForResource;
324     client.didFinishLoadForResource = didFinishLoadForResource;
325     client.didFailLoadForResource = didFailLoadForResource;
326
327     WKBundlePageSetResourceLoadClient(toAPI(&page), &client.base);
328 }
329
330 - (id <WKWebProcessPlugInLoadDelegate>)loadDelegate
331 {
332     return _loadDelegate.getAutoreleased();
333 }
334
335 - (void)setLoadDelegate:(id <WKWebProcessPlugInLoadDelegate>)loadDelegate
336 {
337     _loadDelegate = loadDelegate;
338
339     if (loadDelegate) {
340         setUpPageLoaderClient(self, *_page);
341         setUpResourceLoadClient(self, *_page);
342     } else {
343         WKBundlePageSetPageLoaderClient(toAPI(_page.get()), nullptr);
344         WKBundlePageSetResourceLoadClient(toAPI(_page.get()), nullptr);
345     }
346 }
347
348 - (void)dealloc
349 {
350     if (_remoteObjectRegistry) {
351         WebKit::WebProcess::singleton().removeMessageReceiver(Messages::RemoteObjectRegistry::messageReceiverName(), _page->pageID());
352         [_remoteObjectRegistry _invalidate];
353     }
354
355     _page->~WebPage();
356
357     [super dealloc];
358 }
359
360 - (WKDOMDocument *)mainFrameDocument
361 {
362     WebCore::Frame* webCoreMainFrame = _page->mainFrame();
363     if (!webCoreMainFrame)
364         return nil;
365
366     return WebKit::toWKDOMDocument(webCoreMainFrame->document());
367 }
368
369 - (WKDOMRange *)selectedRange
370 {
371     RefPtr<WebCore::Range> range = _page->currentSelectionAsRange();
372     if (!range)
373         return nil;
374
375     return WebKit::toWKDOMRange(range.get());
376 }
377
378 - (WKWebProcessPlugInFrame *)mainFrame
379 {
380     return wrapper(_page->mainWebFrame());
381 }
382
383 - (WKWebProcessPlugInPageGroup *)pageGroup
384 {
385     return wrapper(*_page->pageGroup());
386 }
387
388 #pragma mark WKObject protocol implementation
389
390 - (API::Object&)_apiObject
391 {
392     return *_page;
393 }
394
395 @end
396
397 @implementation WKWebProcessPlugInBrowserContextController (WKPrivate)
398
399 - (WKBundlePageRef)_bundlePageRef
400 {
401     return toAPI(_page.get());
402 }
403
404 - (WKBrowsingContextHandle *)handle
405 {
406     return [[[WKBrowsingContextHandle alloc] _initWithPageID:_page->pageID()] autorelease];
407 }
408
409 + (instancetype)lookUpBrowsingContextFromHandle:(WKBrowsingContextHandle *)handle
410 {
411     return wrapper(WebKit::WebProcess::singleton().webPage(handle.pageID));
412 }
413
414 - (_WKRemoteObjectRegistry *)_remoteObjectRegistry
415 {
416     if (!_remoteObjectRegistry) {
417         _remoteObjectRegistry = adoptNS([[_WKRemoteObjectRegistry alloc] _initWithWebPage:*_page]);
418         WebKit::WebProcess::singleton().addMessageReceiver(Messages::RemoteObjectRegistry::messageReceiverName(), _page->pageID(), [_remoteObjectRegistry remoteObjectRegistry]);
419     }
420
421     return _remoteObjectRegistry.get();
422 }
423
424 - (id <WKWebProcessPlugInFormDelegatePrivate>)_formDelegate
425 {
426     return _formDelegate.getAutoreleased();
427 }
428
429 - (void)_setFormDelegate:(id <WKWebProcessPlugInFormDelegatePrivate>)formDelegate
430 {
431     _formDelegate = formDelegate;
432
433     class FormClient : public API::InjectedBundle::FormClient {
434     public:
435         explicit FormClient(WKWebProcessPlugInBrowserContextController *controller)
436             : m_controller(controller)
437         {
438         }
439
440         virtual ~FormClient() { }
441
442         void didFocusTextField(WebKit::WebPage*, WebCore::HTMLInputElement* inputElement, WebKit::WebFrame* frame) override
443         {
444             auto formDelegate = m_controller->_formDelegate.get();
445
446             if ([formDelegate respondsToSelector:@selector(_webProcessPlugInBrowserContextController:didFocusTextField:inFrame:)])
447                 [formDelegate _webProcessPlugInBrowserContextController:m_controller didFocusTextField:wrapper(*WebKit::InjectedBundleNodeHandle::getOrCreate(inputElement).get()) inFrame:wrapper(*frame)];
448         }
449
450         void willSendSubmitEvent(WebKit::WebPage*, WebCore::HTMLFormElement* formElement, WebKit::WebFrame* targetFrame, WebKit::WebFrame* sourceFrame, const Vector<std::pair<String, String>>& values) override
451         {
452             auto formDelegate = m_controller->_formDelegate.get();
453
454             if ([formDelegate respondsToSelector:@selector(_webProcessPlugInBrowserContextController:willSendSubmitEventToForm:inFrame:targetFrame:values:)]) {
455                 auto valueMap = adoptNS([[NSMutableDictionary alloc] initWithCapacity:values.size()]);
456                 for (const auto& pair : values)
457                     [valueMap setObject:pair.second forKey:pair.first];
458
459                 [formDelegate _webProcessPlugInBrowserContextController:m_controller willSendSubmitEventToForm:wrapper(*WebKit::InjectedBundleNodeHandle::getOrCreate(formElement).get())
460                     inFrame:wrapper(*sourceFrame) targetFrame:wrapper(*targetFrame) values:valueMap.get()];
461             }
462         }
463
464         static void encodeUserObject(NSObject <NSSecureCoding> *userObject, RefPtr<API::Object>& userData)
465         {
466             if (!userObject)
467                 return;
468
469             auto archiver = secureArchiver();
470             @try {
471                 [archiver encodeObject:userObject forKey:@"userObject"];
472             } @catch (NSException *exception) {
473                 LOG_ERROR("Failed to encode user object: %@", exception);
474                 return;
475             }
476             [archiver finishEncoding];
477
478             userData = API::Data::createWithoutCopying(archiver.get().encodedData);
479         }
480
481         void willSubmitForm(WebKit::WebPage*, WebCore::HTMLFormElement* formElement, WebKit::WebFrame* frame, WebKit::WebFrame* sourceFrame, const Vector<std::pair<WTF::String, WTF::String>>& values, RefPtr<API::Object>& userData) override
482         {
483             auto formDelegate = m_controller->_formDelegate.get();
484
485             if ([formDelegate respondsToSelector:@selector(_webProcessPlugInBrowserContextController:willSubmitForm:toFrame:fromFrame:withValues:)]) {
486                 auto valueMap = adoptNS([[NSMutableDictionary alloc] initWithCapacity:values.size()]);
487                 for (const auto& pair : values)
488                     [valueMap setObject:pair.second forKey:pair.first];
489
490                 NSObject <NSSecureCoding> *userObject = [formDelegate _webProcessPlugInBrowserContextController:m_controller willSubmitForm:wrapper(*WebKit::InjectedBundleNodeHandle::getOrCreate(formElement).get()) toFrame:wrapper(*frame) fromFrame:wrapper(*sourceFrame) withValues:valueMap.get()];
491                 encodeUserObject(userObject, userData);
492             }
493         }
494
495         void textDidChangeInTextField(WebKit::WebPage*, WebCore::HTMLInputElement* inputElement, WebKit::WebFrame* frame, bool initiatedByUserTyping) override
496         {
497             auto formDelegate = m_controller->_formDelegate.get();
498
499             if ([formDelegate respondsToSelector:@selector(_webProcessPlugInBrowserContextController:textDidChangeInTextField:inFrame:initiatedByUserTyping:)])
500                 [formDelegate _webProcessPlugInBrowserContextController:m_controller textDidChangeInTextField:wrapper(*WebKit::InjectedBundleNodeHandle::getOrCreate(inputElement)) inFrame:wrapper(*frame) initiatedByUserTyping:initiatedByUserTyping];
501         }
502
503         void willBeginInputSession(WebKit::WebPage*, WebCore::Element* element, WebKit::WebFrame* frame, bool userIsInteracting, RefPtr<API::Object>& userData) override
504         {
505             auto formDelegate = m_controller->_formDelegate.get();
506
507             if ([formDelegate respondsToSelector:@selector(_webProcessPlugInBrowserContextController:willBeginInputSessionForElement:inFrame:userIsInteracting:)]) {
508                 NSObject<NSSecureCoding> *userObject = [formDelegate _webProcessPlugInBrowserContextController:m_controller willBeginInputSessionForElement:wrapper(*WebKit::InjectedBundleNodeHandle::getOrCreate(element)) inFrame:wrapper(*frame) userIsInteracting:userIsInteracting];
509                 encodeUserObject(userObject, userData);
510             } else if (userIsInteracting && [formDelegate respondsToSelector:@selector(_webProcessPlugInBrowserContextController:willBeginInputSessionForElement:inFrame:)]) {
511                 // FIXME: We check userIsInteracting so that we don't begin an input session for a
512                 // programmatic focus that doesn't cause the keyboard to appear. But this misses the case of
513                 // a programmatic focus happening while the keyboard is already shown. Once we have a way to
514                 // know the keyboard state in the Web Process, we should refine the condition.
515                 NSObject<NSSecureCoding> *userObject = [formDelegate _webProcessPlugInBrowserContextController:m_controller willBeginInputSessionForElement:wrapper(*WebKit::InjectedBundleNodeHandle::getOrCreate(element)) inFrame:wrapper(*frame)];
516                 encodeUserObject(userObject, userData);
517             }
518         }
519
520         bool shouldNotifyOnFormChanges(WebKit::WebPage*) override
521         {
522             auto formDelegate = m_controller->_formDelegate.get();
523
524             if (![formDelegate respondsToSelector:@selector(_webProcessPlugInBrowserContextControllerShouldNotifyOnFormChanges:)])
525                 return false;
526
527             return [formDelegate _webProcessPlugInBrowserContextControllerShouldNotifyOnFormChanges:m_controller];
528         }
529
530         void didAssociateFormControls(WebKit::WebPage*, const Vector<RefPtr<WebCore::Element>>& elements) override
531         {
532             auto formDelegate = m_controller->_formDelegate.get();
533
534             if (![formDelegate respondsToSelector:@selector(_webProcessPlugInBrowserContextController:didAssociateFormControls:)])
535                 return;
536
537             auto controls = adoptNS([[NSMutableArray alloc] initWithCapacity:elements.size()]);
538             for (const auto& element : elements)
539                 [controls addObject:wrapper(*WebKit::InjectedBundleNodeHandle::getOrCreate(element.get()))];
540             return [formDelegate _webProcessPlugInBrowserContextController:m_controller didAssociateFormControls:controls.get()];
541         }
542
543     private:
544         WKWebProcessPlugInBrowserContextController *m_controller;
545     };
546
547     if (formDelegate)
548         _page->setInjectedBundleFormClient(std::make_unique<FormClient>(self));
549     else
550         _page->setInjectedBundleFormClient(nullptr);
551 }
552
553 - (id <WKWebProcessPlugInEditingDelegate>)_editingDelegate
554 {
555     return _editingDelegate.getAutoreleased();
556 }
557
558 static inline WKEditorInsertAction toWK(WebCore::EditorInsertAction action)
559 {
560     switch (action) {
561     case WebCore::EditorInsertAction::Typed:
562         return WKEditorInsertActionTyped;
563     case WebCore::EditorInsertAction::Pasted:
564         return WKEditorInsertActionPasted;
565     case WebCore::EditorInsertAction::Dropped:
566         return WKEditorInsertActionDropped;
567     }
568 }
569
570 - (void)_setEditingDelegate:(id <WKWebProcessPlugInEditingDelegate>)editingDelegate
571 {
572     _editingDelegate = editingDelegate;
573
574     class Client final : public API::InjectedBundle::EditorClient {
575     public:
576         explicit Client(WKWebProcessPlugInBrowserContextController *controller)
577             : m_controller { controller }
578             , m_delegateMethods { m_controller->_editingDelegate.get() }
579         {
580         }
581
582     private:
583         bool shouldInsertText(WebKit::WebPage&, StringImpl* text, WebCore::Range* rangeToReplace, WebCore::EditorInsertAction action) final
584         {
585             if (!m_delegateMethods.shouldInsertText)
586                 return true;
587
588             return [m_controller->_editingDelegate.get() _webProcessPlugInBrowserContextController:m_controller shouldInsertText:String(text) replacingRange:wrapper(*WebKit::InjectedBundleRangeHandle::getOrCreate(rangeToReplace)) givenAction:toWK(action)];
589         }
590
591         bool shouldChangeSelectedRange(WebKit::WebPage&, WebCore::Range* fromRange, WebCore::Range* toRange, WebCore::EAffinity affinity, bool stillSelecting) final
592         {
593             if (!m_delegateMethods.shouldChangeSelectedRange)
594                 return true;
595
596             auto apiFromRange = fromRange ? adoptNS([[WKDOMRange alloc] _initWithImpl:fromRange]) : nil;
597             auto apiToRange = toRange ? adoptNS([[WKDOMRange alloc] _initWithImpl:toRange]) : nil;
598 #if PLATFORM(IOS)
599             UITextStorageDirection apiAffinity = affinity == WebCore::UPSTREAM ? UITextStorageDirectionBackward : UITextStorageDirectionForward;
600 #else
601             NSSelectionAffinity apiAffinity = affinity == WebCore::UPSTREAM ? NSSelectionAffinityUpstream : NSSelectionAffinityDownstream;
602 #endif
603
604             return [m_controller->_editingDelegate.get() _webProcessPlugInBrowserContextController:m_controller shouldChangeSelectedRange:apiFromRange.get() toRange:apiToRange.get() affinity:apiAffinity stillSelecting:stillSelecting];
605         }
606
607         void didChange(WebKit::WebPage&, StringImpl*) final
608         {
609             if (!m_delegateMethods.didChange)
610                 return;
611
612             [m_controller->_editingDelegate.get() _webProcessPlugInBrowserContextControllerDidChangeByEditing:m_controller];
613         }
614
615         void willWriteToPasteboard(WebKit::WebPage&, WebCore::Range* range) final
616         {
617             if (!m_delegateMethods.willWriteToPasteboard)
618                 return;
619
620             [m_controller->_editingDelegate.get() _webProcessPlugInBrowserContextController:m_controller willWriteRangeToPasteboard:wrapper(*WebKit::InjectedBundleRangeHandle::getOrCreate(range).get())];
621         }
622
623         void getPasteboardDataForRange(WebKit::WebPage&, WebCore::Range* range, Vector<String>& pasteboardTypes, Vector<RefPtr<WebCore::SharedBuffer>>& pasteboardData) final
624         {
625             if (!m_delegateMethods.getPasteboardDataForRange)
626                 return;
627
628             auto dataByType = [m_controller->_editingDelegate.get() _webProcessPlugInBrowserContextController:m_controller pasteboardDataForRange:wrapper(*WebKit::InjectedBundleRangeHandle::getOrCreate(range).get())];
629             for (NSString *type in dataByType) {
630                 pasteboardTypes.append(type);
631                 pasteboardData.append(WebCore::SharedBuffer::create(dataByType[type]));
632             };
633         }
634
635         void didWriteToPasteboard(WebKit::WebPage&) final
636         {
637             if (!m_delegateMethods.didWriteToPasteboard)
638                 return;
639
640             [m_controller->_editingDelegate.get() _webProcessPlugInBrowserContextControllerDidWriteToPasteboard:m_controller];
641         }
642
643         bool performTwoStepDrop(WebKit::WebPage&, WebCore::DocumentFragment& fragment, WebCore::Range& range, bool isMove) final
644         {
645             if (!m_delegateMethods.performTwoStepDrop)
646                 return false;
647
648             auto rangeHandle = WebKit::InjectedBundleRangeHandle::getOrCreate(&range);
649             auto nodeHandle = WebKit::InjectedBundleNodeHandle::getOrCreate(&fragment);
650             return [m_controller->_editingDelegate.get() _webProcessPlugInBrowserContextController:m_controller performTwoStepDrop:wrapper(*nodeHandle) atDestination:wrapper(*rangeHandle) isMove:isMove];
651         }
652
653         WTF::String replacementURLForResource(WebKit::WebPage&, Ref<WebCore::SharedBuffer>&& resourceData, const WTF::String& mimeType)
654         {
655             if (!m_delegateMethods.replacementURLForResource)
656                 return { };
657
658             NSString *type = (NSString *)mimeType;
659             auto data = resourceData->createNSData();
660             return [m_controller->_editingDelegate.get() _webProcessPlugInBrowserContextController:m_controller replacementURLForResource:data.get() mimeType:type];
661         }
662
663         WKWebProcessPlugInBrowserContextController *m_controller;
664         const struct DelegateMethods {
665             DelegateMethods(RetainPtr<id <WKWebProcessPlugInEditingDelegate>> delegate)
666                 : shouldInsertText([delegate respondsToSelector:@selector(_webProcessPlugInBrowserContextController:shouldInsertText:replacingRange:givenAction:)])
667                 , shouldChangeSelectedRange([delegate respondsToSelector:@selector(_webProcessPlugInBrowserContextController:shouldChangeSelectedRange:toRange:affinity:stillSelecting:)])
668                 , didChange([delegate respondsToSelector:@selector(_webProcessPlugInBrowserContextControllerDidChangeByEditing:)])
669                 , willWriteToPasteboard([delegate respondsToSelector:@selector(_webProcessPlugInBrowserContextController:willWriteRangeToPasteboard:)])
670                 , getPasteboardDataForRange([delegate respondsToSelector:@selector(_webProcessPlugInBrowserContextController:pasteboardDataForRange:)])
671                 , didWriteToPasteboard([delegate respondsToSelector:@selector(_webProcessPlugInBrowserContextControllerDidWriteToPasteboard:)])
672                 , performTwoStepDrop([delegate respondsToSelector:@selector(_webProcessPlugInBrowserContextController:performTwoStepDrop:atDestination:isMove:)])
673                 , replacementURLForResource([delegate respondsToSelector:@selector(_webProcessPlugInBrowserContextController:replacementURLForResource:mimeType:)])
674             {
675             }
676
677             bool shouldInsertText;
678             bool shouldChangeSelectedRange;
679             bool didChange;
680             bool willWriteToPasteboard;
681             bool getPasteboardDataForRange;
682             bool didWriteToPasteboard;
683             bool performTwoStepDrop;
684             bool replacementURLForResource;
685         } m_delegateMethods;
686     };
687
688     if (editingDelegate)
689         _page->setInjectedBundleEditorClient(std::make_unique<Client>(self));
690     else
691         _page->setInjectedBundleEditorClient(nullptr);
692 }
693
694 - (BOOL)_defersLoading
695 {
696     return _page->defersLoading();
697 }
698
699 - (void)_setDefersLoading:(BOOL)defersLoading
700 {
701     _page->setDefersLoading(defersLoading);
702 }
703
704 - (BOOL)_usesNonPersistentWebsiteDataStore
705 {
706     return _page->usesEphemeralSession();
707 }
708
709 @end
710
711 #endif // WK_API_ENABLED