Unreviewed build fix after r229140.
[WebKit-https.git] / Source / WebKit / WebProcess / cocoa / WebProcessCocoa.mm
1 /*
2  * Copyright (C) 2010-2017 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 "WebProcess.h"
28 #import "WebProcessCocoa.h"
29
30 #import "LegacyCustomProtocolManager.h"
31 #import "LogInitialization.h"
32 #import "Logging.h"
33 #import "ObjCObjectGraph.h"
34 #import "SandboxExtension.h"
35 #import "SandboxInitializationParameters.h"
36 #import "SecItemShim.h"
37 #import "SessionTracker.h"
38 #import "WKAPICast.h"
39 #import "WKBrowsingContextHandleInternal.h"
40 #import "WKCrashReporter.h"
41 #import "WKFullKeyboardAccessWatcher.h"
42 #import "WKTypeRefWrapper.h"
43 #import "WKWebProcessPlugInBrowserContextControllerInternal.h"
44 #import "WebFrame.h"
45 #import "WebInspector.h"
46 #import "WebPage.h"
47 #import "WebProcessCreationParameters.h"
48 #import "WebProcessProxyMessages.h"
49 #import "WebsiteDataStoreParameters.h"
50 #import <JavaScriptCore/ConfigFile.h>
51 #import <JavaScriptCore/Options.h>
52 #import <WebCore/AXObjectCache.h>
53 #import <WebCore/CPUMonitor.h>
54 #import <WebCore/FileSystem.h>
55 #import <WebCore/FontCache.h>
56 #import <WebCore/FontCascade.h>
57 #import <WebCore/LocalizedStrings.h>
58 #import <WebCore/LogInitialization.h>
59 #import <WebCore/MemoryRelease.h>
60 #import <WebCore/NSScrollerImpDetails.h>
61 #import <WebCore/PerformanceLogging.h>
62 #import <WebCore/RuntimeApplicationChecks.h>
63 #import <WebCore/WebCoreNSURLExtras.h>
64 #import <algorithm>
65 #import <dispatch/dispatch.h>
66 #import <objc/runtime.h>
67 #import <pal/spi/cf/CFNetworkSPI.h>
68 #import <pal/spi/cocoa/LaunchServicesSPI.h>
69 #import <pal/spi/cocoa/QuartzCoreSPI.h>
70 #import <pal/spi/cocoa/pthreadSPI.h>
71 #import <pal/spi/mac/NSAccessibilitySPI.h>
72 #import <pal/spi/mac/NSApplicationSPI.h>
73 #import <stdio.h>
74 #import <wtf/CurrentTime.h>
75
76 #if PLATFORM(IOS)
77 #import <UIKit/UIAccessibility.h>
78 #import <pal/spi/ios/GraphicsServicesSPI.h>
79
80 #if USE(APPLE_INTERNAL_SDK)
81 #import <AXRuntime/AXDefines.h>
82 #import <AXRuntime/AXNotificationConstants.h>
83 #else
84 #define kAXPidStatusChangedNotification 0
85 #endif
86
87 #endif
88
89 #if PLATFORM(MAC)
90 #import <WebCore/ScrollbarThemeMac.h>
91 #endif
92
93 #if USE(OS_STATE)
94 #import <os/state_private.h>
95 #endif
96
97 using namespace WebCore;
98
99 namespace WebKit {
100
101 #if PLATFORM(MAC)
102 static const Seconds cpuMonitoringInterval { 8_min };
103 #endif
104
105 void WebProcess::platformSetCacheModel(CacheModel)
106 {
107 }
108
109 #if USE(APPKIT)
110 static id NSApplicationAccessibilityFocusedUIElement(NSApplication*, SEL)
111 {
112     WebPage* page = WebProcess::singleton().focusedWebPage();
113     if (!page || !page->accessibilityRemoteObject())
114         return 0;
115
116     return [page->accessibilityRemoteObject() accessibilityFocusedUIElement];
117 }
118 #endif
119
120 void WebProcess::platformInitializeWebProcess(WebProcessCreationParameters&& parameters)
121 {
122 #if !LOG_DISABLED || !RELEASE_LOG_DISABLED
123     WebCore::initializeLogChannelsIfNecessary(parameters.webCoreLoggingChannels);
124     WebKit::initializeLogChannelsIfNecessary(parameters.webKitLoggingChannels);
125 #endif
126
127     WebCore::setApplicationBundleIdentifier(parameters.uiProcessBundleIdentifier);
128     SessionTracker::setIdentifierBase(parameters.uiProcessBundleIdentifier);
129
130 #if ENABLE(SANDBOX_EXTENSIONS)
131     SandboxExtension::consumePermanently(parameters.uiProcessBundleResourcePathExtensionHandle);
132     SandboxExtension::consumePermanently(parameters.webSQLDatabaseDirectoryExtensionHandle);
133     SandboxExtension::consumePermanently(parameters.applicationCacheDirectoryExtensionHandle);
134     SandboxExtension::consumePermanently(parameters.mediaCacheDirectoryExtensionHandle);
135     SandboxExtension::consumePermanently(parameters.mediaKeyStorageDirectoryExtensionHandle);
136     SandboxExtension::consumePermanently(parameters.javaScriptConfigurationDirectoryExtensionHandle);
137 #if ENABLE(MEDIA_STREAM)
138     SandboxExtension::consumePermanently(parameters.audioCaptureExtensionHandle);
139 #endif
140 #if PLATFORM(IOS)
141     SandboxExtension::consumePermanently(parameters.cookieStorageDirectoryExtensionHandle);
142     SandboxExtension::consumePermanently(parameters.containerCachesDirectoryExtensionHandle);
143     SandboxExtension::consumePermanently(parameters.containerTemporaryDirectoryExtensionHandle);
144 #endif
145 #endif
146
147     if (!parameters.javaScriptConfigurationDirectory.isEmpty()) {
148         String javaScriptConfigFile = parameters.javaScriptConfigurationDirectory + "/JSC.config";
149         JSC::processConfigFile(javaScriptConfigFile.latin1().data(), "com.apple.WebKit.WebContent", parameters.uiProcessBundleIdentifier.latin1().data());
150     }
151
152 #if PLATFORM(MAC)
153     setSharedHTTPCookieStorage(parameters.uiProcessCookieStorageIdentifier);
154 #endif
155
156     auto urlCache = adoptNS([[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:nil]);
157     [NSURLCache setSharedURLCache:urlCache.get()];
158
159 #if PLATFORM(MAC)
160     WebCore::FontCache::setFontWhitelist(parameters.fontWhitelist);
161 #endif
162
163     m_compositingRenderServerPort = WTFMove(parameters.acceleratedCompositingPort);
164
165     WebCore::registerMemoryReleaseNotifyCallbacks();
166     MemoryPressureHandler::ReliefLogger::setLoggingEnabled(parameters.shouldEnableMemoryPressureReliefLogging);
167
168     setEnhancedAccessibility(parameters.accessibilityEnhancedUserInterfaceEnabled);
169
170 #if USE(APPKIT)
171     [[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"NSApplicationCrashOnExceptions" : @YES }];
172
173     // rdar://9118639 accessibilityFocusedUIElement in NSApplication defaults to use the keyWindow. Since there's
174     // no window in WK2, NSApplication needs to use the focused page's focused element.
175     Method methodToPatch = class_getInstanceMethod([NSApplication class], @selector(accessibilityFocusedUIElement));
176     method_setImplementation(methodToPatch, (IMP)NSApplicationAccessibilityFocusedUIElement);
177 #endif
178     
179 #if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101400
180     // Need to initialize accessibility for VoiceOver to work when the WebContent process is using NSRunLoop.
181     // Currently, it is also needed to allocate and initialize an NSApplication object.
182     // FIXME: Remove the following line when rdar://problem/36323569 is fixed.
183     [NSApplication sharedApplication];
184     [NSApplication _accessibilityInitialize];
185 #endif
186
187     _CFNetworkSetATSContext(parameters.networkATSContext.get());
188
189 #if TARGET_OS_IPHONE
190     // Priority decay on iOS 9 is impacting page load time so we fix the priority of the WebProcess' main thread (rdar://problem/22003112).
191     pthread_set_fixedpriority_self();
192 #endif
193 }
194
195 void WebProcess::initializeProcessName(const ChildProcessInitializationParameters& parameters)
196 {
197 #if !PLATFORM(IOS)
198     NSString *applicationName;
199     if (parameters.extraInitializationData.get(ASCIILiteral("inspector-process")) == "1")
200         applicationName = [NSString stringWithFormat:WEB_UI_STRING("%@ Web Inspector", "Visible name of Web Inspector's web process. The argument is the application name."), (NSString *)parameters.uiProcessName];
201 #if ENABLE(SERVICE_WORKER)
202     else if (parameters.extraInitializationData.get(ASCIILiteral("service-worker-process")) == "1")
203         applicationName = [NSString stringWithFormat:WEB_UI_STRING("%@ Service Worker", "Visible name of Service Worker process. The argument is the application name."), (NSString *)parameters.uiProcessName];
204 #endif
205     else
206         applicationName = [NSString stringWithFormat:WEB_UI_STRING("%@ Web Content", "Visible name of the web process. The argument is the application name."), (NSString *)parameters.uiProcessName];
207     _LSSetApplicationInformationItem(kLSDefaultSessionID, _LSGetCurrentApplicationASN(), _kLSDisplayNameKey, (CFStringRef)applicationName, nullptr);
208 #endif
209 }
210
211 static void registerWithAccessibility()
212 {
213 #if USE(APPKIT)
214     [NSAccessibilityRemoteUIElement setRemoteUIApp:YES];
215 #endif
216 #if PLATFORM(IOS)
217     NSString *accessibilityBundlePath = [(NSString *)GSSystemRootDirectory() stringByAppendingString:@"/System/Library/AccessibilityBundles/WebProcessLoader.axbundle"];
218     NSError *error = nil;
219     if (![[NSBundle bundleWithPath:accessibilityBundlePath] loadAndReturnError:&error])
220         LOG_ERROR("Failed to load accessibility bundle at %@: %@", accessibilityBundlePath, error);
221 #endif
222 }
223
224 #if USE(OS_STATE)
225 void WebProcess::registerWithStateDumper()
226 {
227     os_state_add_handler(dispatch_get_main_queue(), ^(os_state_hints_t hints) {
228
229         @autoreleasepool {
230             os_state_data_t os_state = nil;
231
232             // Only gather state on faults and sysdiagnose. It's overkill for
233             // general error messages.
234             if (hints->osh_api == OS_STATE_API_ERROR)
235                 return os_state;
236
237             // Create a dictionary to contain the collected state. This
238             // dictionary will be serialized and passed back to os_state.
239             auto stateDict = adoptNS([[NSMutableDictionary alloc] init]);
240
241             {
242                 auto memoryUsageStats = adoptNS([[NSMutableDictionary alloc] init]);
243                 for (auto& it : PerformanceLogging::memoryUsageStatistics(ShouldIncludeExpensiveComputations::Yes)) {
244                     auto keyString = adoptNS([[NSString alloc] initWithUTF8String:it.key]);
245                     [memoryUsageStats setObject:@(it.value) forKey:keyString.get()];
246                 }
247                 [stateDict setObject:memoryUsageStats.get() forKey:@"Memory Usage Stats"];
248             }
249
250             {
251                 auto jsObjectCounts = adoptNS([[NSMutableDictionary alloc] init]);
252                 for (auto& it : PerformanceLogging::javaScriptObjectCounts()) {
253                     auto keyString = adoptNS([[NSString alloc] initWithUTF8String:it.key]);
254                     [jsObjectCounts setObject:@(it.value) forKey:keyString.get()];
255                 }
256                 [stateDict setObject:jsObjectCounts.get() forKey:@"JavaScript Object Counts"];
257             }
258
259             auto pageLoadTimes = adoptNS([[NSMutableArray alloc] init]);
260             for (auto& page : m_pageMap.values()) {
261                 if (page->usesEphemeralSession())
262                     continue;
263
264                 NSDate* date = [NSDate dateWithTimeIntervalSince1970:page->loadCommitTime().secondsSinceEpoch().seconds()];
265                 [pageLoadTimes addObject:date];
266             }
267
268             // Adding an empty array to the process state may provide an
269             // indication of the existance of private sessions, which we'd like
270             // to hide, so don't add empty arrays.
271             if ([pageLoadTimes count])
272                 [stateDict setObject:pageLoadTimes.get() forKey:@"Page Load Times"];
273
274             // --- Possibly add other state here as other entries in the dictionary. ---
275
276             // Submitting an empty process state object may provide an
277             // indication of the existance of private sessions, which we'd like
278             // to hide, so don't return empty dictionaries.
279             if (![stateDict count])
280                 return os_state;
281
282             // Serialize the accumulated process state so that we can put the
283             // result in an os_state_data_t structure.
284             NSError* error = nil;
285             NSData* data = [NSPropertyListSerialization dataWithPropertyList:stateDict.get() format:NSPropertyListBinaryFormat_v1_0 options:0 error:&error];
286
287             if (!data) {
288                 ASSERT(data);
289                 return os_state;
290             }
291
292             size_t neededSize = OS_STATE_DATA_SIZE_NEEDED(data.length);
293             os_state = (os_state_data_t)malloc(neededSize);
294             if (os_state) {
295                 memset(os_state, 0, neededSize);
296                 os_state->osd_type = OS_STATE_DATA_SERIALIZED_NSCF_OBJECT;
297                 os_state->osd_data_size = data.length;
298                 strlcpy(os_state->osd_title, "WebContent state", sizeof(os_state->osd_title));
299                 memcpy(os_state->osd_data, data.bytes, data.length);
300             }
301
302             return os_state;
303         }
304     });
305 }
306 #endif
307
308 void WebProcess::platformInitializeProcess(const ChildProcessInitializationParameters&)
309 {
310     registerWithAccessibility();
311
312 #if USE(OS_STATE)
313     registerWithStateDumper();
314 #endif
315
316 #if ENABLE(SEC_ITEM_SHIM)
317     initializeSecItemShim(*this);
318 #endif
319 }
320
321 #if USE(APPKIT)
322 void WebProcess::stopRunLoop()
323 {
324 #if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101400
325     ChildProcess::stopNSRunLoop();
326 #else
327     ChildProcess::stopNSAppRunLoop();
328 #endif
329 }
330 #endif
331
332 void WebProcess::platformTerminate()
333 {
334 }
335
336 RetainPtr<CFDataRef> WebProcess::sourceApplicationAuditData() const
337 {
338 #if PLATFORM(IOS)
339     audit_token_t auditToken;
340     ASSERT(parentProcessConnection());
341     if (!parentProcessConnection() || !parentProcessConnection()->getAuditToken(auditToken))
342         return nullptr;
343     return adoptCF(CFDataCreate(nullptr, (const UInt8*)&auditToken, sizeof(auditToken)));
344 #else
345     return nullptr;
346 #endif
347 }
348
349 void WebProcess::initializeSandbox(const ChildProcessInitializationParameters& parameters, SandboxInitializationParameters& sandboxParameters)
350 {
351 #if ENABLE(WEB_PROCESS_SANDBOX)
352 #if ENABLE(MANUAL_SANDBOXING)
353     // Need to override the default, because service has a different bundle ID.
354 #if WK_API_ENABLED
355     NSBundle *webKit2Bundle = [NSBundle bundleForClass:NSClassFromString(@"WKWebView")];
356 #else
357     NSBundle *webKit2Bundle = [NSBundle bundleForClass:NSClassFromString(@"WKView")];
358 #endif
359 #if PLATFORM(IOS)
360     sandboxParameters.setOverrideSandboxProfilePath([webKit2Bundle pathForResource:@"com.apple.WebKit.WebContent" ofType:@"sb"]);
361 #else
362     sandboxParameters.setOverrideSandboxProfilePath([webKit2Bundle pathForResource:@"com.apple.WebProcess" ofType:@"sb"]);
363 #endif
364     ChildProcess::initializeSandbox(parameters, sandboxParameters);
365 #endif
366 #else
367     UNUSED_PARAM(parameters);
368     UNUSED_PARAM(sandboxParameters);
369 #endif
370 }
371
372 #if PLATFORM(MAC)
373
374 static NSURL *origin(WebPage& page)
375 {
376     WebFrame* mainFrame = page.mainWebFrame();
377     if (!mainFrame)
378         return nil;
379
380     URL mainFrameURL(URL(), mainFrame->url());
381     Ref<SecurityOrigin> mainFrameOrigin = SecurityOrigin::create(mainFrameURL);
382     String mainFrameOriginString;
383     if (!mainFrameOrigin->isUnique())
384         mainFrameOriginString = mainFrameOrigin->toRawString();
385     else
386         mainFrameOriginString = makeString(mainFrameURL.protocol(), ':'); // toRawString() is not supposed to work with unique origins, and would just return "://".
387
388     // +[NSURL URLWithString:] returns nil when its argument is malformed. It's unclear when we would have a malformed URL here,
389     // but it happens in practice according to <rdar://problem/14173389>. Leaving an assertion in to catch a reproducible case.
390     ASSERT([NSURL URLWithString:mainFrameOriginString]);
391
392     return [NSURL URLWithString:mainFrameOriginString];
393 }
394
395 #endif
396
397 void WebProcess::updateActivePages()
398 {
399 #if PLATFORM(MAC)
400     auto activePageURLs = adoptNS([[NSMutableArray alloc] init]);
401
402     for (auto& page : m_pageMap.values()) {
403         if (page->usesEphemeralSession())
404             continue;
405
406         if (NSURL *originAsURL = origin(*page))
407             [activePageURLs addObject:userVisibleString(originAsURL)];
408     }
409
410     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), [activePageURLs] {
411         _LSSetApplicationInformationItem(kLSDefaultSessionID, _LSGetCurrentApplicationASN(), CFSTR("LSActivePageUserVisibleOriginsKey"), (__bridge CFArrayRef)activePageURLs.get(), nullptr);
412     });
413 #endif
414 }
415
416 void WebProcess::updateCPULimit()
417 {
418 #if PLATFORM(MAC)
419     std::optional<double> cpuLimit;
420
421     // Use the largest limit among all pages in this process.
422     for (auto& page : m_pageMap.values()) {
423         auto pageCPULimit = page->cpuLimit();
424         if (!pageCPULimit) {
425             cpuLimit = std::nullopt;
426             break;
427         }
428         if (!cpuLimit || pageCPULimit > cpuLimit.value())
429             cpuLimit = pageCPULimit;
430     }
431
432     if (m_cpuLimit == cpuLimit)
433         return;
434
435     m_cpuLimit = cpuLimit;
436     updateCPUMonitorState(CPUMonitorUpdateReason::LimitHasChanged);
437 #endif
438 }
439
440 void WebProcess::updateCPUMonitorState(CPUMonitorUpdateReason reason)
441 {
442 #if PLATFORM(MAC)
443     if (!m_cpuLimit) {
444         if (m_cpuMonitor)
445             m_cpuMonitor->setCPULimit(std::nullopt);
446         return;
447     }
448
449     if (!m_cpuMonitor) {
450         m_cpuMonitor = std::make_unique<CPUMonitor>(cpuMonitoringInterval, [this](double cpuUsage) {
451             RELEASE_LOG(PerformanceLogging, "%p - WebProcess exceeded CPU limit of %.1f%% (was using %.1f%%) hasVisiblePages? %d", this, m_cpuLimit.value() * 100, cpuUsage * 100, hasVisibleWebPage());
452             parentProcessConnection()->send(Messages::WebProcessProxy::DidExceedCPULimit(), 0);
453         });
454     } else if (reason == CPUMonitorUpdateReason::VisibilityHasChanged) {
455         // If the visibility has changed, stop the CPU monitor before setting its limit. This is needed because the CPU usage can vary wildly based on visibility and we would
456         // not want to report that a process has exceeded its background CPU limit even though most of the CPU time was used while the process was visible.
457         m_cpuMonitor->setCPULimit(std::nullopt);
458     }
459     m_cpuMonitor->setCPULimit(m_cpuLimit.value());
460 #else
461     UNUSED_PARAM(reason);
462 #endif
463 }
464
465 RefPtr<ObjCObjectGraph> WebProcess::transformHandlesToObjects(ObjCObjectGraph& objectGraph)
466 {
467     struct Transformer final : ObjCObjectGraph::Transformer {
468         Transformer(WebProcess& webProcess)
469             : m_webProcess(webProcess)
470         {
471         }
472
473         bool shouldTransformObject(id object) const override
474         {
475 #if WK_API_ENABLED
476             if (dynamic_objc_cast<WKBrowsingContextHandle>(object))
477                 return true;
478
479             if (dynamic_objc_cast<WKTypeRefWrapper>(object))
480                 return true;
481 #endif
482             return false;
483         }
484
485         RetainPtr<id> transformObject(id object) const override
486         {
487 #if WK_API_ENABLED
488             if (auto* handle = dynamic_objc_cast<WKBrowsingContextHandle>(object)) {
489                 if (auto* webPage = m_webProcess.webPage(handle._pageID))
490                     return wrapper(*webPage);
491
492                 return [NSNull null];
493             }
494
495             if (auto* wrapper = dynamic_objc_cast<WKTypeRefWrapper>(object))
496                 return adoptNS([[WKTypeRefWrapper alloc] initWithObject:toAPI(m_webProcess.transformHandlesToObjects(toImpl(wrapper.object)).get())]);
497 #endif
498             return object;
499         }
500
501         WebProcess& m_webProcess;
502     };
503
504     return ObjCObjectGraph::create(ObjCObjectGraph::transform(objectGraph.rootObject(), Transformer(*this)).get());
505 }
506
507 RefPtr<ObjCObjectGraph> WebProcess::transformObjectsToHandles(ObjCObjectGraph& objectGraph)
508 {
509     struct Transformer final : ObjCObjectGraph::Transformer {
510         bool shouldTransformObject(id object) const override
511         {
512 #if WK_API_ENABLED
513             if (dynamic_objc_cast<WKWebProcessPlugInBrowserContextController>(object))
514                 return true;
515
516             if (dynamic_objc_cast<WKTypeRefWrapper>(object))
517                 return true;
518 #endif
519
520             return false;
521         }
522
523         RetainPtr<id> transformObject(id object) const override
524         {
525 #if WK_API_ENABLED
526             if (auto* controller = dynamic_objc_cast<WKWebProcessPlugInBrowserContextController>(object))
527                 return controller.handle;
528
529             if (auto* wrapper = dynamic_objc_cast<WKTypeRefWrapper>(object))
530                 return adoptNS([[WKTypeRefWrapper alloc] initWithObject:toAPI(transformObjectsToHandles(toImpl(wrapper.object)).get())]);
531 #endif
532             return object;
533         }
534     };
535
536     return ObjCObjectGraph::create(ObjCObjectGraph::transform(objectGraph.rootObject(), Transformer()).get());
537 }
538
539 void WebProcess::destroyRenderingResources()
540 {
541 #if !RELEASE_LOG_DISABLED
542     double startTime = monotonicallyIncreasingTime();
543 #endif
544     CABackingStoreCollectBlocking();
545 #if !RELEASE_LOG_DISABLED
546     double endTime = monotonicallyIncreasingTime();
547 #endif
548     RELEASE_LOG(ProcessSuspension, "%p - WebProcess::destroyRenderingResources() took %.2fms", this, (endTime - startTime) * 1000.0);
549 }
550
551 // FIXME: This should live somewhere else, and it should have the implementation in line instead of calling out to WKSI.
552 void _WKSetCrashReportApplicationSpecificInformation(NSString *infoString)
553 {
554     return setCrashReportApplicationSpecificInformation((__bridge CFStringRef)infoString);
555 }
556
557 #if PLATFORM(IOS)
558 void WebProcess::accessibilityProcessSuspendedNotification(bool suspended)
559 {
560     UIAccessibilityPostNotification(kAXPidStatusChangedNotification, @{ @"pid" : @(getpid()), @"suspended" : @(suspended) });
561 }
562 #endif
563
564 #if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101400
565 void WebProcess::scrollerStylePreferenceChanged(bool useOverlayScrollbars)
566 {
567     ScrollerStyle::setUseOverlayScrollbars(useOverlayScrollbars);
568
569     ScrollbarTheme& theme = ScrollbarTheme::theme();
570     if (theme.isMockTheme())
571         return;
572
573     static_cast<ScrollbarThemeMac&>(theme).preferencesChanged();
574 }
575 #endif    
576
577 } // namespace WebKit