Have insertDictatedTextAsync() take an InsertTextOptions
[WebKit-https.git] / Source / WebKit / UIProcess / Cocoa / WebPageProxyCocoa.mm
1 /*
2  * Copyright (C) 2014-2019 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 "WebPageProxy.h"
28
29 #import "APIAttachment.h"
30 #import "APIUIClient.h"
31 #import "DataDetectionResult.h"
32 #import "InsertTextOptions.h"
33 #import "LoadParameters.h"
34 #import "PageClient.h"
35 #import "SafeBrowsingSPI.h"
36 #import "SafeBrowsingWarning.h"
37 #import "SharedBufferDataReference.h"
38 #import "WebPageMessages.h"
39 #import "WebProcessProxy.h"
40 #import "WebsiteDataStore.h"
41 #import <WebCore/DragItem.h>
42 #import <WebCore/NotImplemented.h>
43 #import <WebCore/SearchPopupMenuCocoa.h>
44 #import <WebCore/ValidationBubble.h>
45 #import <wtf/BlockPtr.h>
46 #import <wtf/cf/TypeCastsCF.h>
47
48 #if USE(DICTATION_ALTERNATIVES)
49 #import <WebCore/TextAlternativeWithRange.h>
50 #endif
51
52 namespace WebKit {
53 using namespace WebCore;
54
55 #if ENABLE(DATA_DETECTION)
56 void WebPageProxy::setDataDetectionResult(const DataDetectionResult& dataDetectionResult)
57 {
58     m_dataDetectionResults = dataDetectionResult.results;
59 }
60 #endif
61
62 void WebPageProxy::saveRecentSearches(const String& name, const Vector<WebCore::RecentSearch>& searchItems)
63 {
64     if (!name) {
65         // FIXME: This should be a message check.
66         return;
67     }
68
69     WebCore::saveRecentSearches(name, searchItems);
70 }
71
72 void WebPageProxy::loadRecentSearches(const String& name, CompletionHandler<void(Vector<WebCore::RecentSearch>&&)>&& completionHandler)
73 {
74     if (!name) {
75         // FIXME: This should be a message check.
76         return completionHandler({ });
77     }
78
79     completionHandler(WebCore::loadRecentSearches(name));
80 }
81
82 void WebPageProxy::beginSafeBrowsingCheck(const URL& url, bool forMainFrameNavigation, WebFramePolicyListenerProxy& listener)
83 {
84 #if HAVE(SAFE_BROWSING)
85     SSBLookupContext *context = [SSBLookupContext sharedLookupContext];
86     if (!context)
87         return listener.didReceiveSafeBrowsingResults({ });
88     [context lookUpURL:url completionHandler:makeBlockPtr([listener = makeRef(listener), forMainFrameNavigation, url = url] (SSBLookupResult *result, NSError *error) mutable {
89         RunLoop::main().dispatch([listener = WTFMove(listener), result = retainPtr(result), error = retainPtr(error), forMainFrameNavigation, url = WTFMove(url)] {
90             if (error) {
91                 listener->didReceiveSafeBrowsingResults({ });
92                 return;
93             }
94
95             for (SSBServiceLookupResult *lookupResult in [result serviceLookupResults]) {
96                 if (lookupResult.isPhishing || lookupResult.isMalware || lookupResult.isUnwantedSoftware) {
97                     listener->didReceiveSafeBrowsingResults(SafeBrowsingWarning::create(url, forMainFrameNavigation, lookupResult));
98                     return;
99                 }
100             }
101             listener->didReceiveSafeBrowsingResults({ });
102         });
103     }).get()];
104 #else
105     listener.didReceiveSafeBrowsingResults({ });
106 #endif
107 }
108
109 #if ENABLE(CONTENT_FILTERING)
110 void WebPageProxy::contentFilterDidBlockLoadForFrame(const WebCore::ContentFilterUnblockHandler& unblockHandler, FrameIdentifier frameID)
111 {
112     contentFilterDidBlockLoadForFrameShared(m_process.copyRef(), unblockHandler, frameID);
113 }
114
115 void WebPageProxy::contentFilterDidBlockLoadForFrameShared(Ref<WebProcessProxy>&& process, const WebCore::ContentFilterUnblockHandler& unblockHandler, FrameIdentifier frameID)
116 {
117     if (WebFrameProxy* frame = process->webFrame(frameID))
118         frame->contentFilterDidBlockLoad(unblockHandler);
119 }
120 #endif
121
122 void WebPageProxy::addPlatformLoadParameters(LoadParameters& loadParameters)
123 {
124     loadParameters.dataDetectionContext = m_uiClient->dataDetectionContext();
125 }
126
127 void WebPageProxy::createSandboxExtensionsIfNeeded(const Vector<String>& files, SandboxExtension::Handle& fileReadHandle, SandboxExtension::HandleArray& fileUploadHandles)
128 {
129     if (!files.size())
130         return;
131
132     if (files.size() == 1) {
133         BOOL isDirectory;
134         if ([[NSFileManager defaultManager] fileExistsAtPath:files[0] isDirectory:&isDirectory] && !isDirectory) {
135 #if HAVE(SANDBOX_ISSUE_READ_EXTENSION_TO_PROCESS_BY_AUDIT_TOKEN)
136             ASSERT(process().connection() && process().connection()->getAuditToken());
137             if (process().connection() && process().connection()->getAuditToken())
138                 SandboxExtension::createHandleForReadByAuditToken("/", *(process().connection()->getAuditToken()), fileReadHandle);
139             else
140                 SandboxExtension::createHandle("/", SandboxExtension::Type::ReadOnly, fileReadHandle);
141 #else
142             SandboxExtension::createHandle("/", SandboxExtension::Type::ReadOnly, fileReadHandle);
143 #endif
144             willAcquireUniversalFileReadSandboxExtension(m_process);
145         }
146     }
147
148     fileUploadHandles.allocate(files.size());
149     for (size_t i = 0; i< files.size(); i++) {
150         NSString *file = files[i];
151         if (![[NSFileManager defaultManager] fileExistsAtPath:file])
152             continue;
153         SandboxExtension::createHandle(file, SandboxExtension::Type::ReadOnly, fileUploadHandles[i]);
154     }
155 }
156
157 bool WebPageProxy::scrollingUpdatesDisabledForTesting()
158 {
159     return pageClient().scrollingUpdatesDisabledForTesting();
160 }
161
162 #if ENABLE(DRAG_SUPPORT)
163
164 void WebPageProxy::startDrag(const DragItem& dragItem, const ShareableBitmap::Handle& dragImageHandle)
165 {
166     pageClient().startDrag(dragItem, dragImageHandle);
167 }
168
169 // FIXME: Move these functions to WebPageProxyIOS.mm.
170 #if PLATFORM(IOS_FAMILY)
171
172 void WebPageProxy::setPromisedDataForImage(const String&, const SharedMemory::Handle&, uint64_t, const String&, const String&, const String&, const String&, const String&, const SharedMemory::Handle&, uint64_t)
173 {
174     notImplemented();
175 }
176
177 void WebPageProxy::setDragCaretRect(const IntRect& dragCaretRect)
178 {
179     if (m_currentDragCaretRect == dragCaretRect)
180         return;
181
182     auto previousRect = m_currentDragCaretRect;
183     m_currentDragCaretRect = dragCaretRect;
184     pageClient().didChangeDragCaretRect(previousRect, dragCaretRect);
185 }
186
187 #endif // PLATFORM(IOS_FAMILY)
188
189 #endif // ENABLE(DRAG_SUPPORT)
190
191 #if ENABLE(ATTACHMENT_ELEMENT)
192
193 void WebPageProxy::platformRegisterAttachment(Ref<API::Attachment>&& attachment, const String& preferredFileName, const IPC::SharedBufferDataReference& dataReference)
194 {
195     if (dataReference.isEmpty())
196         return;
197
198     auto fileWrapper = adoptNS([pageClient().allocFileWrapperInstance() initRegularFileWithContents:dataReference.buffer()->createNSData().autorelease()]);
199     [fileWrapper setPreferredFilename:preferredFileName];
200     attachment->setFileWrapper(fileWrapper.get());
201 }
202
203 void WebPageProxy::platformRegisterAttachment(Ref<API::Attachment>&& attachment, const String& filePath)
204 {
205     if (!filePath)
206         return;
207
208     auto fileWrapper = adoptNS([pageClient().allocFileWrapperInstance() initWithURL:[NSURL fileURLWithPath:filePath] options:0 error:nil]);
209     attachment->setFileWrapper(fileWrapper.get());
210 }
211
212 void WebPageProxy::platformCloneAttachment(Ref<API::Attachment>&& fromAttachment, Ref<API::Attachment>&& toAttachment)
213 {
214     toAttachment->setFileWrapper(fromAttachment->fileWrapper());
215 }
216
217 #endif // ENABLE(ATTACHMENT_ELEMENT)
218     
219 void WebPageProxy::performDictionaryLookupAtLocation(const WebCore::FloatPoint& point)
220 {
221     if (!hasRunningProcess())
222         return;
223     
224     process().send(Messages::WebPage::PerformDictionaryLookupAtLocation(point), m_webPageID);
225 }
226
227 void WebPageProxy::performDictionaryLookupOfCurrentSelection()
228 {
229     if (!hasRunningProcess())
230         return;
231     
232     process().send(Messages::WebPage::PerformDictionaryLookupOfCurrentSelection(), m_webPageID);
233 }
234
235 void WebPageProxy::insertDictatedTextAsync(const String& text, const EditingRange& replacementRange, const Vector<TextAlternativeWithRange>& dictationAlternativesWithRange, InsertTextOptions&& options)
236 {
237 #if USE(DICTATION_ALTERNATIVES)
238     if (!hasRunningProcess())
239         return;
240
241     Vector<DictationAlternative> dictationAlternatives;
242     for (const auto& alternativeWithRange : dictationAlternativesWithRange) {
243         uint64_t dictationContext = pageClient().addDictationAlternatives(alternativeWithRange.alternatives);
244         if (dictationContext)
245             dictationAlternatives.append(DictationAlternative(alternativeWithRange.range.location, alternativeWithRange.range.length, dictationContext));
246     }
247
248     if (dictationAlternatives.isEmpty()) {
249         insertTextAsync(text, replacementRange, WTFMove(options));
250         return;
251     }
252
253     process().send(Messages::WebPage::InsertDictatedTextAsync { text, replacementRange, dictationAlternatives, WTFMove(options) }, m_webPageID);
254 #else
255     insertTextAsync(text, replacementRange, WTFMove(options));
256 #endif
257 }
258     
259 #if ENABLE(APPLE_PAY)
260
261 IPC::Connection* WebPageProxy::paymentCoordinatorConnection(const WebPaymentCoordinatorProxy&)
262 {
263     return messageSenderConnection();
264 }
265
266 const String& WebPageProxy::paymentCoordinatorBoundInterfaceIdentifier(const WebPaymentCoordinatorProxy&)
267 {
268     return websiteDataStore().configuration().boundInterfaceIdentifier();
269 }
270
271 const String& WebPageProxy::paymentCoordinatorSourceApplicationBundleIdentifier(const WebPaymentCoordinatorProxy&)
272 {
273     return websiteDataStore().configuration().sourceApplicationBundleIdentifier();
274 }
275
276 const String& WebPageProxy::paymentCoordinatorSourceApplicationSecondaryIdentifier(const WebPaymentCoordinatorProxy&)
277 {
278     return websiteDataStore().configuration().sourceApplicationSecondaryIdentifier();
279 }
280
281 void WebPageProxy::paymentCoordinatorAddMessageReceiver(WebPaymentCoordinatorProxy&, const IPC::StringReference& messageReceiverName, IPC::MessageReceiver& messageReceiver)
282 {
283     process().addMessageReceiver(messageReceiverName, m_webPageID, messageReceiver);
284 }
285
286 void WebPageProxy::paymentCoordinatorRemoveMessageReceiver(WebPaymentCoordinatorProxy&, const IPC::StringReference& messageReceiverName)
287 {
288     process().removeMessageReceiver(messageReceiverName, m_webPageID);
289 }
290
291 #endif
292
293 #if ENABLE(SPEECH_SYNTHESIS)
294 void WebPageProxy::didStartSpeaking(WebCore::PlatformSpeechSynthesisUtterance&)
295 {
296     if (speechSynthesisData().speakingStartedCompletionHandler)
297         speechSynthesisData().speakingStartedCompletionHandler();
298 }
299
300 void WebPageProxy::didFinishSpeaking(WebCore::PlatformSpeechSynthesisUtterance&)
301 {
302     if (speechSynthesisData().speakingFinishedCompletionHandler)
303         speechSynthesisData().speakingFinishedCompletionHandler();
304 }
305
306 void WebPageProxy::didPauseSpeaking(WebCore::PlatformSpeechSynthesisUtterance&)
307 {
308     if (speechSynthesisData().speakingPausedCompletionHandler)
309         speechSynthesisData().speakingPausedCompletionHandler();
310 }
311
312 void WebPageProxy::didResumeSpeaking(WebCore::PlatformSpeechSynthesisUtterance&)
313 {
314     if (speechSynthesisData().speakingResumedCompletionHandler)
315         speechSynthesisData().speakingResumedCompletionHandler();
316 }
317
318 void WebPageProxy::speakingErrorOccurred(WebCore::PlatformSpeechSynthesisUtterance&)
319 {
320     process().send(Messages::WebPage::SpeakingErrorOccurred(), m_webPageID);
321 }
322
323 void WebPageProxy::boundaryEventOccurred(WebCore::PlatformSpeechSynthesisUtterance&, WebCore::SpeechBoundary speechBoundary, unsigned charIndex)
324 {
325     process().send(Messages::WebPage::BoundaryEventOccurred(speechBoundary == WebCore::SpeechBoundary::SpeechWordBoundary, charIndex), m_webPageID);
326 }
327
328 void WebPageProxy::voicesDidChange()
329 {
330     process().send(Messages::WebPage::VoicesDidChange(), m_webPageID);
331 }
332 #endif // ENABLE(SPEECH_SYNTHESIS)
333
334 #if HAVE(VISIBILITY_PROPAGATION_VIEW)
335 void WebPageProxy::didCreateContextForVisibilityPropagation(LayerHostingContextID contextID)
336 {
337     m_contextIDForVisibilityPropagation = contextID;
338     pageClient().didCreateContextForVisibilityPropagation(contextID);
339 }
340
341 void WebPageProxy::didCreateContextInGPUProcessForVisibilityPropagation(LayerHostingContextID contextID)
342 {
343     pageClient().didCreateContextInGPUProcessForVisibilityPropagation(contextID);
344 }
345 #endif
346
347 void WebPageProxy::grantAccessToPreferenceService()
348 {
349 #if ENABLE(CFPREFS_DIRECT_MODE)
350     process().unblockPreferenceServiceIfNeeded();
351 #endif
352 }
353
354 } // namespace WebKit