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