Add support for DataDetectors in WK (iOS).
[WebKit-https.git] / Source / WebKit2 / UIProcess / API / Cocoa / WKWebViewConfiguration.mm
1 /*
2  * Copyright (C) 2014, 2015 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 "WKWebViewConfigurationInternal.h"
28
29 #if WK_API_ENABLED
30
31 #import "APIPageConfiguration.h"
32 #import "WKPreferences.h"
33 #import "WKProcessPool.h"
34 #import "WKUserContentController.h"
35 #import "WKWebViewContentProviderRegistry.h"
36 #import "WeakObjCPtr.h"
37 #import "_WKVisitedLinkProvider.h"
38 #import "_WKWebsiteDataStoreInternal.h"
39 #import <wtf/RetainPtr.h>
40
41 #if PLATFORM(IOS)
42 #import "UIKitSPI.h"
43 #import <WebCore/Device.h>
44 #endif
45
46 template<typename T> class LazyInitialized {
47 public:
48     typedef typename WTF::GetPtrHelper<T>::PtrType PtrType;
49
50     template<typename F>
51     PtrType get(F&& f)
52     {
53         if (!m_isInitialized) {
54             m_value = f();
55             m_isInitialized = true;
56         }
57
58         return m_value.get();
59     }
60
61     void set(PtrType t)
62     {
63         m_value = t;
64         m_isInitialized = true;
65     }
66
67     void set(T&& t)
68     {
69         m_value = WTFMove(t);
70         m_isInitialized = true;
71     }
72
73     PtrType peek()
74     {
75         return m_value.get();
76     }
77
78 private:
79     bool m_isInitialized = false;
80     T m_value;
81 };
82
83 @implementation WKWebViewConfiguration {
84     LazyInitialized<RetainPtr<WKProcessPool>> _processPool;
85     LazyInitialized<RetainPtr<WKPreferences>> _preferences;
86     LazyInitialized<RetainPtr<WKUserContentController>> _userContentController;
87     LazyInitialized<RetainPtr<_WKVisitedLinkStore>> _visitedLinkStore;
88     LazyInitialized<RetainPtr<WKWebsiteDataStore>> _websiteDataStore;
89     WebKit::WeakObjCPtr<WKWebView> _relatedWebView;
90     WebKit::WeakObjCPtr<WKWebView> _alternateWebViewForNavigationGestures;
91     BOOL _treatsSHA1SignedCertificatesAsInsecure;
92     RetainPtr<NSString> _groupIdentifier;
93     LazyInitialized<RetainPtr<NSString>> _applicationNameForUserAgent;
94     BOOL _respectsImageOrientation;
95     BOOL _printsBackgrounds;
96     CGFloat _incrementalRenderingSuppressionTimeout;
97     BOOL _allowsJavaScriptMarkup;
98     BOOL _convertsPositionStyleOnCopy;
99     BOOL _allowsMetaRefresh;
100
101 #if PLATFORM(IOS)
102     LazyInitialized<RetainPtr<WKWebViewContentProviderRegistry>> _contentProviderRegistry;
103     BOOL _alwaysRunsAtForegroundPriority;
104     BOOL _allowsInlineMediaPlayback;
105     BOOL _inlineMediaPlaybackRequiresPlaysInlineAttribute;
106     BOOL _invisibleAutoplayNotPermitted;
107     BOOL _mediaDataLoadsAutomatically;
108     BOOL _requiresUserActionForAudioPlayback;
109 #endif
110 #if PLATFORM(MAC)
111     BOOL _showsURLsInToolTips;
112     BOOL _serviceControlsEnabled;
113     BOOL _imageControlsEnabled;
114 #endif
115 }
116
117 - (instancetype)init
118 {
119     if (!(self = [super init]))
120         return nil;
121     
122 #if PLATFORM(IOS)
123     _requiresUserActionForMediaPlayback = YES;
124     _requiresUserActionForAudioPlayback = YES;
125     _allowsPictureInPictureMediaPlayback = YES;
126     _allowsInlineMediaPlayback = WebCore::deviceClass() == MGDeviceClassiPad;
127     _inlineMediaPlaybackRequiresPlaysInlineAttribute = !_allowsInlineMediaPlayback;
128     _invisibleAutoplayNotPermitted = YES;
129     _mediaDataLoadsAutomatically = NO;
130     _respectsImageOrientation = YES;
131     _printsBackgrounds = YES;
132 #endif
133
134 #if PLATFORM(MAC)
135     _printsBackgrounds = NO;
136     _respectsImageOrientation = NO;
137     _showsURLsInToolTips = NO;
138     _serviceControlsEnabled = NO;
139     _imageControlsEnabled = NO;
140 #endif
141
142 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
143     _allowsAirPlayForMediaPlayback = YES;
144 #endif
145
146     _incrementalRenderingSuppressionTimeout = 5;
147     _allowsJavaScriptMarkup = YES;
148     _convertsPositionStyleOnCopy = NO;
149     _allowsMetaRefresh = YES;
150
151     return self;
152 }
153
154 - (NSString *)description
155 {
156     return [NSString stringWithFormat:@"<%@: %p; processPool = %@; preferences = %@>", NSStringFromClass(self.class), self, self.processPool, self.preferences];
157 }
158
159 - (id)copyWithZone:(NSZone *)zone
160 {
161     WKWebViewConfiguration *configuration = [(WKWebViewConfiguration *)[[self class] allocWithZone:zone] init];
162
163     configuration.processPool = self.processPool;
164     configuration.preferences = self.preferences;
165     configuration.userContentController = self.userContentController;
166     configuration.websiteDataStore = self.websiteDataStore;
167     configuration._visitedLinkStore = self._visitedLinkStore;
168     configuration._relatedWebView = _relatedWebView.get().get();
169     configuration._alternateWebViewForNavigationGestures = _alternateWebViewForNavigationGestures.get().get();
170     configuration->_treatsSHA1SignedCertificatesAsInsecure = _treatsSHA1SignedCertificatesAsInsecure;
171 #if PLATFORM(IOS)
172     configuration._contentProviderRegistry = self._contentProviderRegistry;
173 #endif
174
175     configuration->_suppressesIncrementalRendering = self->_suppressesIncrementalRendering;
176     configuration.applicationNameForUserAgent = self.applicationNameForUserAgent;
177
178     configuration->_respectsImageOrientation = self->_respectsImageOrientation;
179     configuration->_printsBackgrounds = self->_printsBackgrounds;
180     configuration->_incrementalRenderingSuppressionTimeout = self->_incrementalRenderingSuppressionTimeout;
181     configuration->_allowsJavaScriptMarkup = self->_allowsJavaScriptMarkup;
182     configuration->_convertsPositionStyleOnCopy = self->_convertsPositionStyleOnCopy;
183     configuration->_allowsMetaRefresh = self->_allowsMetaRefresh;
184
185 #if PLATFORM(IOS)
186     configuration->_allowsInlineMediaPlayback = self->_allowsInlineMediaPlayback;
187     configuration->_inlineMediaPlaybackRequiresPlaysInlineAttribute = self->_inlineMediaPlaybackRequiresPlaysInlineAttribute;
188     configuration->_invisibleAutoplayNotPermitted = self->_invisibleAutoplayNotPermitted;
189     configuration->_mediaDataLoadsAutomatically = self->_mediaDataLoadsAutomatically;
190     configuration->_allowsPictureInPictureMediaPlayback = self->_allowsPictureInPictureMediaPlayback;
191     configuration->_alwaysRunsAtForegroundPriority = _alwaysRunsAtForegroundPriority;
192     configuration->_requiresUserActionForMediaPlayback = self->_requiresUserActionForMediaPlayback;
193     configuration->_requiresUserActionForAudioPlayback = self->_requiresUserActionForAudioPlayback;
194     configuration->_selectionGranularity = self->_selectionGranularity;
195 #endif
196 #if PLATFORM(MAC)
197     configuration->_showsURLsInToolTips = self->_showsURLsInToolTips;
198     configuration->_serviceControlsEnabled = self->_serviceControlsEnabled;
199     configuration->_imageControlsEnabled = self->_imageControlsEnabled;
200 #endif
201 #if ENABLE(DATA_DETECTION)
202     configuration->_dataDetectorTypes = self->_dataDetectorTypes;
203 #endif
204 #if ENABLE(WIRELESS_TARGET_PLAYBACK)
205     configuration->_allowsAirPlayForMediaPlayback = self->_allowsAirPlayForMediaPlayback;
206 #endif
207
208     return configuration;
209 }
210
211 - (WKProcessPool *)processPool
212 {
213     return _processPool.get([] { return adoptNS([[WKProcessPool alloc] init]); });
214 }
215
216 - (void)setProcessPool:(WKProcessPool *)processPool
217 {
218     _processPool.set(processPool);
219 }
220
221 - (WKPreferences *)preferences
222 {
223     return _preferences.get([] { return adoptNS([[WKPreferences alloc] init]); });
224 }
225
226 - (void)setPreferences:(WKPreferences *)preferences
227 {
228     _preferences.set(preferences);
229 }
230
231 - (WKUserContentController *)userContentController
232 {
233     return _userContentController.get([] { return adoptNS([[WKUserContentController alloc] init]); });
234 }
235
236 - (void)setUserContentController:(WKUserContentController *)userContentController
237 {
238     _userContentController.set(userContentController);
239 }
240
241 - (WKWebsiteDataStore *)websiteDataStore
242 {
243     return _websiteDataStore.get([] { return [WKWebsiteDataStore defaultDataStore]; });
244 }
245
246 - (void)setWebsiteDataStore:(WKWebsiteDataStore *)websiteDataStore
247 {
248     _websiteDataStore.set(websiteDataStore);
249 }
250
251 static NSString *defaultApplicationNameForUserAgent()
252 {
253 #if PLATFORM(IOS)
254     return [@"Mobile/" stringByAppendingString:[UIDevice currentDevice].buildVersion];
255 #else
256     return nil;
257 #endif
258 }
259
260 - (NSString *)applicationNameForUserAgent
261 {
262     return _applicationNameForUserAgent.get([] { return defaultApplicationNameForUserAgent(); });
263 }
264
265 - (void)setApplicationNameForUserAgent:(NSString *)applicationNameForUserAgent
266 {
267     _applicationNameForUserAgent.set(adoptNS([applicationNameForUserAgent copy]));
268 }
269
270 - (_WKVisitedLinkStore *)_visitedLinkStore
271 {
272     return _visitedLinkStore.get([] { return adoptNS([[_WKVisitedLinkStore alloc] init]); });
273 }
274
275 - (void)_setVisitedLinkStore:(_WKVisitedLinkStore *)visitedLinkStore
276 {
277     _visitedLinkStore.set(visitedLinkStore);
278 }
279
280 #pragma clang diagnostic push
281 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
282
283 - (_WKWebsiteDataStore *)_websiteDataStore
284 {
285     return self.websiteDataStore ? adoptNS([[_WKWebsiteDataStore alloc] initWithDataStore:self.websiteDataStore]).autorelease() : nullptr;
286 }
287
288 - (void)_setWebsiteDataStore:(_WKWebsiteDataStore *)websiteDataStore
289 {
290     self.websiteDataStore = websiteDataStore ? websiteDataStore->_dataStore.get() : nullptr;
291 }
292
293 -(_WKVisitedLinkProvider *)_visitedLinkProvider
294 {
295     return (_WKVisitedLinkProvider *)self._visitedLinkStore;
296 }
297
298 - (void)_setVisitedLinkProvider:(_WKVisitedLinkProvider *)_visitedLinkProvider
299 {
300     self._visitedLinkStore = _visitedLinkProvider;
301 }
302
303 #pragma clang diagnostic pop
304
305 #if PLATFORM(IOS)
306 - (WKWebViewContentProviderRegistry *)_contentProviderRegistry
307 {
308     return _contentProviderRegistry.get([] { return adoptNS([[WKWebViewContentProviderRegistry alloc] init]); });
309 }
310
311 - (void)_setContentProviderRegistry:(WKWebViewContentProviderRegistry *)registry
312 {
313     _contentProviderRegistry.set(registry);
314 }
315 #endif
316
317 - (void)_validate
318 {
319     if (!self.processPool)
320         [NSException raise:NSInvalidArgumentException format:@"configuration.processPool is nil"];
321
322     if (!self.preferences)
323         [NSException raise:NSInvalidArgumentException format:@"configuration.preferences is nil"];
324
325     if (!self.userContentController)
326         [NSException raise:NSInvalidArgumentException format:@"configuration.userContentController is nil"];
327
328     if (!self.websiteDataStore)
329         [NSException raise:NSInvalidArgumentException format:@"configuration.websiteDataStore is nil"];
330
331     if (!self._visitedLinkStore)
332         [NSException raise:NSInvalidArgumentException format:@"configuration._visitedLinkStore is nil"];
333
334 #if PLATFORM(IOS)
335     if (!self._contentProviderRegistry)
336         [NSException raise:NSInvalidArgumentException format:@"configuration._contentProviderRegistry is nil"];
337 #endif
338 }
339
340 @end
341
342 @implementation WKWebViewConfiguration (WKPrivate)
343
344 - (WKWebView *)_relatedWebView
345 {
346     return _relatedWebView.getAutoreleased();
347 }
348
349 - (void)_setRelatedWebView:(WKWebView *)relatedWebView
350 {
351     _relatedWebView = relatedWebView;
352 }
353
354 - (WKWebView *)_alternateWebViewForNavigationGestures
355 {
356     return _alternateWebViewForNavigationGestures.getAutoreleased();
357 }
358
359 - (void)_setAlternateWebViewForNavigationGestures:(WKWebView *)alternateView
360 {
361     _alternateWebViewForNavigationGestures = alternateView;
362 }
363
364 - (NSString *)_groupIdentifier
365 {
366     return _groupIdentifier.get();
367 }
368
369 - (void)_setGroupIdentifier:(NSString *)groupIdentifier
370 {
371     _groupIdentifier = groupIdentifier;
372 }
373
374 - (BOOL)_treatsSHA1SignedCertificatesAsInsecure
375 {
376     return _treatsSHA1SignedCertificatesAsInsecure;
377 }
378
379 - (void)_setTreatsSHA1SignedCertificatesAsInsecure:(BOOL)insecure
380 {
381     _treatsSHA1SignedCertificatesAsInsecure = insecure;
382 }
383
384 - (BOOL)_respectsImageOrientation
385 {
386     return _respectsImageOrientation;
387 }
388
389 - (void)_setRespectsImageOrientation:(BOOL)respectsImageOrientation
390 {
391     _respectsImageOrientation = respectsImageOrientation;
392 }
393
394 - (BOOL)_printsBackgrounds
395 {
396     return _printsBackgrounds;
397 }
398
399 - (void)_setPrintsBackgrounds:(BOOL)printsBackgrounds
400 {
401     _printsBackgrounds = printsBackgrounds;
402 }
403
404 - (CGFloat)_incrementalRenderingSuppressionTimeout
405 {
406     return _incrementalRenderingSuppressionTimeout;
407 }
408
409 - (void)_setIncrementalRenderingSuppressionTimeout:(CGFloat)incrementalRenderingSuppressionTimeout
410 {
411     _incrementalRenderingSuppressionTimeout = incrementalRenderingSuppressionTimeout;
412 }
413
414 - (BOOL)_allowsJavaScriptMarkup
415 {
416     return _allowsJavaScriptMarkup;
417 }
418
419 - (void)_setAllowsJavaScriptMarkup:(BOOL)allowsJavaScriptMarkup
420 {
421     _allowsJavaScriptMarkup = allowsJavaScriptMarkup;
422 }
423
424 - (BOOL)_convertsPositionStyleOnCopy
425 {
426     return _convertsPositionStyleOnCopy;
427 }
428
429 - (void)_setConvertsPositionStyleOnCopy:(BOOL)convertsPositionStyleOnCopy
430 {
431     _convertsPositionStyleOnCopy = convertsPositionStyleOnCopy;
432 }
433
434 - (BOOL)_allowsMetaRefresh
435 {
436     return _allowsMetaRefresh;
437 }
438
439 - (void)_setAllowsMetaRefresh:(BOOL)allowsMetaRefresh
440 {
441     _allowsMetaRefresh = allowsMetaRefresh;
442 }
443
444 #if PLATFORM(IOS)
445 - (BOOL)_alwaysRunsAtForegroundPriority
446 {
447     return _alwaysRunsAtForegroundPriority;
448 }
449
450 - (void)_setAlwaysRunsAtForegroundPriority:(BOOL)alwaysRunsAtForegroundPriority
451 {
452     _alwaysRunsAtForegroundPriority = alwaysRunsAtForegroundPriority;
453 }
454
455 - (BOOL)_inlineMediaPlaybackRequiresPlaysInlineAttribute
456 {
457     return _inlineMediaPlaybackRequiresPlaysInlineAttribute;
458 }
459
460 - (void)_setInlineMediaPlaybackRequiresPlaysInlineAttribute:(BOOL)requires
461 {
462     _inlineMediaPlaybackRequiresPlaysInlineAttribute = requires;
463 }
464
465 - (BOOL)_invisibleAutoplayNotPermitted
466 {
467     return _invisibleAutoplayNotPermitted;
468 }
469
470 - (void)_setInvisibleAutoplayNotPermitted:(BOOL)notPermitted
471 {
472     _invisibleAutoplayNotPermitted = notPermitted;
473 }
474
475 - (BOOL)_mediaDataLoadsAutomatically
476 {
477     return _mediaDataLoadsAutomatically;
478 }
479
480 - (void)_setMediaDataLoadsAutomatically:(BOOL)mediaDataLoadsAutomatically
481 {
482     _mediaDataLoadsAutomatically = mediaDataLoadsAutomatically;
483 }
484
485 - (BOOL)_requiresUserActionForAudioPlayback
486 {
487     return _requiresUserActionForAudioPlayback;
488 }
489
490 - (void)_setRequiresUserActionForAudioPlayback:(BOOL)requiresUserActionForAudioPlayback
491 {
492     _requiresUserActionForAudioPlayback = requiresUserActionForAudioPlayback;
493 }
494
495 #endif // PLATFORM(IOS)
496
497 #if PLATFORM(MAC)
498 - (BOOL)_showsURLsInToolTips
499 {
500     return _showsURLsInToolTips;
501 }
502
503 - (void)_setShowsURLsInToolTips:(BOOL)showsURLsInToolTips
504 {
505     _showsURLsInToolTips = showsURLsInToolTips;
506 }
507
508 - (BOOL)_serviceControlsEnabled
509 {
510     return _serviceControlsEnabled;
511 }
512
513 - (void)_setServiceControlsEnabled:(BOOL)serviceControlsEnabled
514 {
515     _serviceControlsEnabled = serviceControlsEnabled;
516 }
517
518 - (BOOL)_imageControlsEnabled
519 {
520     return _imageControlsEnabled;
521 }
522
523 - (void)_setImageControlsEnabled:(BOOL)imageControlsEnabled
524 {
525     _imageControlsEnabled = imageControlsEnabled;
526 }
527 #endif // PLATFORM(MAC)
528
529 @end
530
531 @implementation WKWebViewConfiguration (WKDeprecated)
532
533 #if PLATFORM(IOS)
534 - (BOOL)mediaPlaybackAllowsAirPlay
535 {
536     return self.allowsAirPlayForMediaPlayback;
537 }
538
539 - (void)setMediaPlaybackAllowsAirPlay:(BOOL)allowed
540 {
541     self.allowsAirPlayForMediaPlayback = allowed;
542 }
543
544 - (BOOL)mediaPlaybackRequiresUserAction
545 {
546     return self.requiresUserActionForMediaPlayback;
547 }
548
549 - (void)setMediaPlaybackRequiresUserAction:(BOOL)required
550 {
551     self.requiresUserActionForMediaPlayback = required;
552 }
553 #endif // PLATFORM(IOS)
554
555 @end
556
557 #endif // WK_API_ENABLED