https://bugs.webkit.org/show_bug.cgi?id=132417
<rdar://problem/
16535921>
Reviewed by Anders Carlsson.
Reorganize takeViewSnapshot to return a ViewSnaphot with the image
filled in (the other properties are filled in by ViewSnapshotStore).
Make ViewSnapshotStore use a fixed size instead of count for the snapshot cache.
iOS doesn't use purgeable snapshots, so make the cache much smaller there.
Use CARenderServerCaptureLayerWithTransform to achieve async snapshotting.
Rename WebKit::ViewSnapshotStore::Snapshot to WebKit::ViewSnapshot so that
it can be forward-declared in a bunch of places.
* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView _takeViewSnapshot:]):
Use CARenderServerCaptureLayerWithTransform.
* UIProcess/API/Cocoa/WKWebViewInternal.h:
* UIProcess/API/mac/WKView.mm:
(createIOSurfaceFromImage):
(-[WKView _takeViewSnapshot:]):
Adjust to the new push model.
* UIProcess/API/mac/WKViewInternal.h:
* UIProcess/PageClient.h:
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::takeViewSnapshot):
* UIProcess/WebPageProxy.h:
* UIProcess/ios/PageClientImplIOS.h:
* UIProcess/ios/PageClientImplIOS.mm:
(WebKit::PageClientImpl::takeViewSnapshot):
* UIProcess/mac/PageClientImpl.h:
* UIProcess/mac/PageClientImpl.mm:
(WebKit::PageClientImpl::takeViewSnapshot):
Plumbing.
* UIProcess/ios/ViewGestureControllerIOS.mm:
(WebKit::ViewGestureController::beginSwipeGesture):
(WebKit::ViewGestureController::endSwipeGesture):
Realize an object that can be used as the layer contents from the slot ID.
* UIProcess/ios/WebMemoryPressureHandlerIOS.cpp:
(WebKit::WebMemoryPressureHandler::sharedHandler):
(WebKit::WebMemoryPressureHandler::WebMemoryPressureHandler):
* UIProcess/WebMemoryPressureHandlerIOS.h:
Add a memory pressure handler for the UI process. This does not use
WebCore's platform independent memory pressure handler because that
mechanism only allows for one handler per process, and we don't want to
stomp on any handlers installed by WebKit1 in a process where the WebKits coexist.
* UIProcess/ios/WKContentView.h:
* UIProcess/ios/WKContentView.mm:
(-[WKContentView _takeViewSnapshot]): Deleted.
Get rid of an unnecessary bounce through WKContentView.
* UIProcess/mac/ViewGestureControllerMac.mm:
(WebKit::ViewGestureController::retrieveSnapshotForItem):
(WebKit::ViewGestureController::endSwipeGesture):
Use the new name, ViewSnapshot.
* UIProcess/mac/ViewSnapshotStore.h:
(WebKit::ViewSnapshot::ViewSnapshot):
* UIProcess/mac/ViewSnapshotStore.mm:
(WebKit::ViewSnapshotStore::ViewSnapshotStore):
(WebKit::ViewSnapshotStore::~ViewSnapshotStore):
(WebKit::ViewSnapshotStore::snapshottingContext):
Use a custom CAContext for snapshotting so that snapshots don't
disappear when the main context is destroyed on hibernation.
(WebKit::ViewSnapshotStore::removeSnapshotImage):
(WebKit::ViewSnapshotStore::pruneSnapshots):
(WebKit::ViewSnapshotStore::recordSnapshot):
(WebKit::ViewSnapshotStore::getSnapshot):
(WebKit::ViewSnapshotStore::discardSnapshots):
(WebKit::ViewSnapshot::clearImage):
(WebKit::ViewSnapshot::hasImage):
(WebKit::createIOSurfaceFromImage): Deleted.
(WebKit::ViewSnapshotStore::Snapshot::clearImage): Deleted.
(WebKit::ViewSnapshotStore::Snapshot::hasImage): Deleted.
Cache by image size instead of counts.
* WebKit2.xcodeproj/project.pbxproj:
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@168260
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2014-05-05 Tim Horton <timothy_horton@apple.com>
+
+ [iOS WebKit2] Swipe snapshots should be taken asynchronously
+ https://bugs.webkit.org/show_bug.cgi?id=132417
+ <rdar://problem/16535921>
+
+ Reviewed by Anders Carlsson.
+
+ Reorganize takeViewSnapshot to return a ViewSnaphot with the image
+ filled in (the other properties are filled in by ViewSnapshotStore).
+
+ Make ViewSnapshotStore use a fixed size instead of count for the snapshot cache.
+ iOS doesn't use purgeable snapshots, so make the cache much smaller there.
+
+ Use CARenderServerCaptureLayerWithTransform to achieve async snapshotting.
+
+ Rename WebKit::ViewSnapshotStore::Snapshot to WebKit::ViewSnapshot so that
+ it can be forward-declared in a bunch of places.
+
+ * UIProcess/API/Cocoa/WKWebView.mm:
+ (-[WKWebView _takeViewSnapshot:]):
+ Use CARenderServerCaptureLayerWithTransform.
+
+ * UIProcess/API/Cocoa/WKWebViewInternal.h:
+ * UIProcess/API/mac/WKView.mm:
+ (createIOSurfaceFromImage):
+ (-[WKView _takeViewSnapshot:]):
+ Adjust to the new push model.
+
+ * UIProcess/API/mac/WKViewInternal.h:
+ * UIProcess/PageClient.h:
+ * UIProcess/WebPageProxy.cpp:
+ (WebKit::WebPageProxy::takeViewSnapshot):
+ * UIProcess/WebPageProxy.h:
+ * UIProcess/ios/PageClientImplIOS.h:
+ * UIProcess/ios/PageClientImplIOS.mm:
+ (WebKit::PageClientImpl::takeViewSnapshot):
+ * UIProcess/mac/PageClientImpl.h:
+ * UIProcess/mac/PageClientImpl.mm:
+ (WebKit::PageClientImpl::takeViewSnapshot):
+ Plumbing.
+
+ * UIProcess/ios/ViewGestureControllerIOS.mm:
+ (WebKit::ViewGestureController::beginSwipeGesture):
+ (WebKit::ViewGestureController::endSwipeGesture):
+ Realize an object that can be used as the layer contents from the slot ID.
+
+ * UIProcess/ios/WebMemoryPressureHandlerIOS.cpp:
+ (WebKit::WebMemoryPressureHandler::sharedHandler):
+ (WebKit::WebMemoryPressureHandler::WebMemoryPressureHandler):
+ * UIProcess/WebMemoryPressureHandlerIOS.h:
+ Add a memory pressure handler for the UI process. This does not use
+ WebCore's platform independent memory pressure handler because that
+ mechanism only allows for one handler per process, and we don't want to
+ stomp on any handlers installed by WebKit1 in a process where the WebKits coexist.
+
+ * UIProcess/ios/WKContentView.h:
+ * UIProcess/ios/WKContentView.mm:
+ (-[WKContentView _takeViewSnapshot]): Deleted.
+ Get rid of an unnecessary bounce through WKContentView.
+
+ * UIProcess/mac/ViewGestureControllerMac.mm:
+ (WebKit::ViewGestureController::retrieveSnapshotForItem):
+ (WebKit::ViewGestureController::endSwipeGesture):
+ Use the new name, ViewSnapshot.
+
+ * UIProcess/mac/ViewSnapshotStore.h:
+ (WebKit::ViewSnapshot::ViewSnapshot):
+ * UIProcess/mac/ViewSnapshotStore.mm:
+ (WebKit::ViewSnapshotStore::ViewSnapshotStore):
+ (WebKit::ViewSnapshotStore::~ViewSnapshotStore):
+ (WebKit::ViewSnapshotStore::snapshottingContext):
+ Use a custom CAContext for snapshotting so that snapshots don't
+ disappear when the main context is destroyed on hibernation.
+
+ (WebKit::ViewSnapshotStore::removeSnapshotImage):
+ (WebKit::ViewSnapshotStore::pruneSnapshots):
+ (WebKit::ViewSnapshotStore::recordSnapshot):
+ (WebKit::ViewSnapshotStore::getSnapshot):
+ (WebKit::ViewSnapshotStore::discardSnapshots):
+ (WebKit::ViewSnapshot::clearImage):
+ (WebKit::ViewSnapshot::hasImage):
+ (WebKit::createIOSurfaceFromImage): Deleted.
+ (WebKit::ViewSnapshotStore::Snapshot::clearImage): Deleted.
+ (WebKit::ViewSnapshotStore::Snapshot::hasImage): Deleted.
+ Cache by image size instead of counts.
+
+ * WebKit2.xcodeproj/project.pbxproj:
+
2014-05-04 Pratik Solanki <psolanki@apple.com>
Reduce calls to CFURLCacheCopySharedURLCache
#import "RemoteObjectRegistryMessages.h"
#import "UIDelegate.h"
#import "ViewGestureController.h"
+#import "ViewSnapshotStore.h"
#import "WKBackForwardListInternal.h"
#import "WKBackForwardListItemInternal.h"
#import "WKBrowsingContextHandleInternal.h"
#import "WebCertificateInfo.h"
#import "WebContext.h"
#import "WebFormSubmissionListenerProxy.h"
+#import "WebKitSystemInterface.h"
#import "WebPageGroup.h"
#import "WebPageProxy.h"
#import "WebProcessProxy.h"
#import "WKWebViewContentProviderRegistry.h"
#import <CoreGraphics/CGFloat.h>
#import <UIKit/UIPeripheralHost_Private.h>
+#import <QuartzCore/CARenderServer.h>
+#import <QuartzCore/QuartzCorePrivate.h>
@interface UIScrollView (UIScrollViewInternal)
- (void)_adjustForAutomaticKeyboardInfo:(NSDictionary*)info animated:(BOOL)animated lastAdjustment:(CGFloat*)lastAdjustment;
}
}
-- (RetainPtr<CGImageRef>)_takeViewSnapshot
+- (WebKit::ViewSnapshot)_takeViewSnapshot
{
- // FIXME: We should be able to use acquire an IOSurface directly, instead of going to CGImage here and back in ViewSnapshotStore.
- UIGraphicsBeginImageContextWithOptions(self.bounds.size, YES, self.window.screen.scale);
- [self drawViewHierarchyInRect:[self bounds] afterScreenUpdates:NO];
- UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
- return image.CGImage;
+ float deviceScale = wkGetScreenScaleFactor();
+ CGSize snapshotSize = self.bounds.size;
+ snapshotSize.width *= deviceScale;
+ snapshotSize.height *= deviceScale;
+
+ WebKit::ViewSnapshot snapshot;
+ snapshot.slotID = [WebKit::ViewSnapshotStore::snapshottingContext() createImageSlot:snapshotSize hasAlpha:YES];
+
+ CATransform3D transform = CATransform3DMakeScale(deviceScale, deviceScale, 1);
+ CARenderServerCaptureLayerWithTransform(MACH_PORT_NULL, self.layer.context.contextId, (uint64_t)self.layer, snapshot.slotID, 0, 0, &transform);
+
+ snapshot.imageSizeInBytes = snapshotSize.width * snapshotSize.height * 4;
+
+ return snapshot;
}
- (void)_zoomToPoint:(WebCore::FloatPoint)point atScale:(double)scale
namespace WebKit {
class WebPageProxy;
+struct ViewSnapshot;
}
@interface WKWebView () WK_WEB_VIEW_PROTOCOLS {
- (void)_dynamicViewportUpdateChangedTargetToScale:(double)newScale position:(CGPoint)newScrollPosition;
-- (RetainPtr<CGImageRef>)_takeViewSnapshot;
+- (WebKit::ViewSnapshot)_takeViewSnapshot;
- (void)_scrollToContentOffset:(WebCore::FloatPoint)contentOffset;
- (BOOL)_scrollToRect:(WebCore::FloatRect)targetRect origin:(WebCore::FloatPoint)origin minimumScrollDistance:(float)minimumScrollDistance;
return _data->_rootLayer.get();
}
-- (RetainPtr<CGImageRef>)_takeViewSnapshot
+static RefPtr<IOSurface> createIOSurfaceFromImage(CGImageRef image)
+{
+ size_t width = CGImageGetWidth(image);
+ size_t height = CGImageGetHeight(image);
+
+ RefPtr<IOSurface> surface = IOSurface::create(IntSize(width, height), ColorSpaceDeviceRGB);
+ RetainPtr<CGContextRef> surfaceContext = surface->ensurePlatformContext();
+ CGContextDrawImage(surfaceContext.get(), CGRectMake(0, 0, width, height), image);
+ CGContextFlush(surfaceContext.get());
+
+ return surface;
+}
+
+- (ViewSnapshot)_takeViewSnapshot
{
NSWindow *window = self.window;
+ ViewSnapshot snapshot;
+
if (![window windowNumber])
- return nullptr;
+ return snapshot;
// FIXME: This should use CGWindowListCreateImage once <rdar://problem/15709646> is resolved.
CGSWindowID windowID = [window windowNumber];
NSRect croppedImageRect = windowCaptureRect;
croppedImageRect.origin.y = windowScreenRect.size.height - windowCaptureScreenRect.size.height - NSMinY(windowCaptureRect);
- return adoptCF(CGImageCreateWithImageInRect(windowSnapshotImage.get(), NSRectToCGRect([window convertRectToBacking:croppedImageRect])));
+ auto croppedSnapshotImage = adoptCF(CGImageCreateWithImageInRect(windowSnapshotImage.get(), NSRectToCGRect([window convertRectToBacking:croppedImageRect])));
+
+ snapshot.surface = createIOSurfaceFromImage(croppedSnapshotImage.get());
+ snapshot.imageSizeInBytes = snapshot.surface->totalBytes();
+ return snapshot;
}
- (void)_wheelEventWasNotHandledByWebCore:(NSEvent *)event
@class WKWebViewConfiguration;
namespace IPC {
- class DataReference;
+class DataReference;
}
namespace WebCore {
- struct KeypressCommand;
- class Image;
- class SharedBuffer;
+class Image;
+class SharedBuffer;
+struct KeypressCommand;
}
namespace WebKit {
class WebContext;
struct ColorSpaceData;
struct EditorState;
+struct ViewSnapshot;
struct WebPageConfiguration;
}
- (void)_setAcceleratedCompositingModeRootLayer:(CALayer *)rootLayer;
- (CALayer *)_acceleratedCompositingModeRootLayer;
-- (RetainPtr<CGImageRef>)_takeViewSnapshot;
+- (WebKit::ViewSnapshot)_takeViewSnapshot;
- (void)_wheelEventWasNotHandledByWebCore:(NSEvent *)event;
- (void)_setAccessibilityWebProcessToken:(NSData *)data;
#endif
namespace WebCore {
- class Cursor;
- struct ViewportAttributes;
+class Cursor;
+struct ViewportAttributes;
}
namespace WebKit {
class WebContextMenuProxy;
class WebEditCommandProxy;
class WebPopupMenuProxy;
+struct ViewSnapshot;
#if ENABLE(TOUCH_EVENTS)
class NativeWebTouchEvent;
virtual void makeFirstResponder() = 0;
virtual void setAcceleratedCompositingRootLayer(LayerOrView *) = 0;
virtual LayerOrView *acceleratedCompositingRootLayer() const = 0;
- virtual RetainPtr<CGImageRef> takeViewSnapshot() = 0;
+ virtual ViewSnapshot takeViewSnapshot() = 0;
virtual void wheelEventWasNotHandledByWebCore(const NativeWebWheelEvent&) = 0;
virtual void clearCustomSwipeViews() = 0;
#endif
#endif // PLATFORM(MAC)
#if PLATFORM(COCOA)
-RetainPtr<CGImageRef> WebPageProxy::takeViewSnapshot()
+ViewSnapshot WebPageProxy::takeViewSnapshot()
{
return m_pageClient.takeViewSnapshot();
}
struct EditorState;
struct PlatformPopupMenuData;
struct PrintInfo;
+struct ViewSnapshot;
struct WebPopupItem;
#if ENABLE(VIBRATION)
void recordNavigationSnapshot();
#if PLATFORM(COCOA)
- RetainPtr<CGImageRef> takeViewSnapshot();
+ ViewSnapshot takeViewSnapshot();
#endif
#if ENABLE(SUBTLE_CRYPTO)
virtual LayerOrView *acceleratedCompositingRootLayer() const override;
virtual LayerHostingMode viewLayerHostingMode() override { return LayerHostingMode::OutOfProcess; }
- virtual RetainPtr<CGImageRef> takeViewSnapshot() override;
+ virtual ViewSnapshot takeViewSnapshot() override;
virtual void wheelEventWasNotHandledByWebCore(const NativeWebWheelEvent&) override;
virtual void clearCustomSwipeViews() override;
#import "FindIndicator.h"
#import "NativeWebKeyboardEvent.h"
#import "InteractionInformationAtPosition.h"
+#import "ViewSnapshotStore.h"
#import "WKContentView.h"
#import "WKContentViewInteraction.h"
#import "WKWebViewInternal.h"
return nullptr;
}
-RetainPtr<CGImageRef> PageClientImpl::takeViewSnapshot()
+ViewSnapshot PageClientImpl::takeViewSnapshot()
{
- return [m_contentView _takeViewSnapshot];
+ return [m_webView _takeViewSnapshot];
}
void PageClientImpl::wheelEventWasNotHandledByWebCore(const NativeWebWheelEvent& event)
#import "WebPageProxy.h"
#import "WebProcessProxy.h"
#import <WebCore/IOSurface.h>
-#import <QuartzCore/QuartzCore.h>
+#import <QuartzCore/QuartzCorePrivate.h>
#import <UIKit/UIScreenEdgePanGestureRecognizer.h>
#import <UIKit/UIViewControllerTransitioning_Private.h>
#import <UIKit/UIWebTouchEventsGestureRecognizer.h>
RetainPtr<UIViewController> snapshotViewController = adoptNS([[UIViewController alloc] init]);
m_snapshotView = adoptNS([[UIView alloc] initWithFrame:liveSwipeViewFrame]);
- ViewSnapshotStore::Snapshot snapshot;
- if (ViewSnapshotStore::shared().getSnapshot(targetItem, snapshot)) {
-#if USE(IOSURFACE)
- if (snapshot.surface->setIsVolatile(false) == IOSurface::SurfaceState::Valid) {
- [m_snapshotView layer].contents = (id)snapshot.surface->surface();
- m_currentSwipeSnapshotSurface = snapshot.surface;
- }
-#else
- [m_snapshotView layer].contents = (id)snapshot.image.get();
-#endif
- }
+ ViewSnapshot snapshot;
+ if (ViewSnapshotStore::shared().getSnapshot(targetItem, snapshot) && snapshot.hasImage())
+ [m_snapshotView layer].contents = [CAContext objectForSlot:snapshot.slotID];
+
[m_snapshotView setBackgroundColor:[UIColor whiteColor]];
- [m_snapshotView layer].contentsGravity = @"topLeft";
+ [m_snapshotView layer].contentsGravity = kCAGravityTopLeft;
[m_snapshotView layer].contentsScale = m_liveSwipeView.window.screen.scale;
[snapshotViewController setView:m_snapshotView.get()];
return;
}
- ViewSnapshotStore::Snapshot snapshot;
+ ViewSnapshot snapshot;
m_targetRenderTreeSize = 0;
if (ViewSnapshotStore::shared().getSnapshot(targetItem, snapshot))
m_targetRenderTreeSize = snapshot.renderTreeSize * swipeSnapshotRemovalRenderTreeSizeTargetFraction;
- (void)_decidePolicyForGeolocationRequestFromOrigin:(WebKit::WebSecurityOrigin&)origin frame:(WebKit::WebFrameProxy&)frame request:(WebKit::GeolocationPermissionRequestProxy&)permissionRequest;
-- (RetainPtr<CGImageRef>)_takeViewSnapshot;
- (void)_setAccessibilityWebProcessToken:(NSData *)data;
- (BOOL)_scrollToRect:(CGRect)targetRect withOrigin:(CGPoint)origin minimumScrollDistance:(CGFloat)minimumScrollDistance;
[[wrapper(_page->process().context()) _geolocationProvider] decidePolicyForGeolocationRequestFromOrigin:toAPI(&origin) frame:toAPI(&frame) request:toAPI(&permissionRequest) window:[self window]];
}
-- (RetainPtr<CGImageRef>)_takeViewSnapshot
-{
- return [_webView _takeViewSnapshot];
-}
-
- (BOOL)_scrollToRect:(CGRect)targetRect withOrigin:(CGPoint)origin minimumScrollDistance:(CGFloat)minimumScrollDistance
{
return [_webView _scrollToRect:targetRect origin:origin minimumScrollDistance:minimumScrollDistance];
--- /dev/null
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WebMemoryPressureHandlerIOS.h"
+
+#if PLATFORM(IOS)
+
+#include "ViewSnapshotStore.h"
+#include <dispatch/private.h>
+
+using namespace WebCore;
+
+namespace WebKit {
+
+WebMemoryPressureHandler& WebMemoryPressureHandler::shared()
+{
+ static NeverDestroyed<WebMemoryPressureHandler> memoryPressureHandler;
+ return memoryPressureHandler;
+}
+
+WebMemoryPressureHandler::WebMemoryPressureHandler()
+{
+ // FIXME: This should be able to share code with WebCore's MemoryPressureHandler (and be platform independent).
+ // Right now it cannot because WebKit1 and WebKit2 need to be able to coexist in the UI process,
+ // and you can only have one WebCore::MemoryPressureHandler.
+
+ dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MEMORYSTATUS, 0, DISPATCH_MEMORYSTATUS_PRESSURE_WARN, dispatch_get_main_queue());
+ dispatch_set_context(source, this);
+ dispatch_source_set_event_handler(source, ^{
+ ViewSnapshotStore::shared().discardSnapshots();
+ });
+ dispatch_resume(source);
+}
+
+} // namespace WebKit
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WebMemoryPressureHandler_h
+#define WebMemoryPressureHandler_h
+
+#if PLATFORM(IOS)
+
+#include <wtf/NeverDestroyed.h>
+
+namespace WebKit {
+
+class WebMemoryPressureHandler {
+ friend class NeverDestroyed<WebMemoryPressureHandler>;
+public:
+ static WebMemoryPressureHandler& shared();
+
+private:
+ WebMemoryPressureHandler();
+};
+
+} // namespace WebKit
+
+#endif // PLATFORM(IOS)
+
+#endif // WebMemoryPressureHandler_h
virtual void exitAcceleratedCompositingMode();
virtual void updateAcceleratedCompositingMode(const LayerTreeContext&);
- virtual RetainPtr<CGImageRef> takeViewSnapshot() override;
+ virtual ViewSnapshot takeViewSnapshot() override;
virtual void wheelEventWasNotHandledByWebCore(const NativeWebWheelEvent&) override;
virtual void clearCustomSwipeViews() override;
#import "NativeWebKeyboardEvent.h"
#import "NativeWebWheelEvent.h"
#import "StringUtilities.h"
+#import "ViewSnapshotStore.h"
#import "WKAPICast.h"
#import "WKFullScreenWindowController.h"
#import "WKStringCF.h"
return m_wkView._acceleratedCompositingModeRootLayer;
}
-RetainPtr<CGImageRef> PageClientImpl::takeViewSnapshot()
+ViewSnapshot PageClientImpl::takeViewSnapshot()
{
return [m_wkView _takeViewSnapshot];
}
IOSurface* ViewGestureController::retrieveSnapshotForItem(WebBackForwardListItem* targetItem, FloatSize swipeLayerSize, float topContentInset)
{
- ViewSnapshotStore::Snapshot snapshot;
+ ViewSnapshot snapshot;
if (!ViewSnapshotStore::shared().getSnapshot(targetItem, snapshot))
return nullptr;
return;
}
- ViewSnapshotStore::Snapshot snapshot;
+ ViewSnapshot snapshot;
uint64_t renderTreeSize = 0;
if (ViewSnapshotStore::shared().getSnapshot(targetItem, snapshot))
renderTreeSize = snapshot.renderTreeSize;
#include <wtf/RetainPtr.h>
#include <wtf/text/WTFString.h>
+OBJC_CLASS CAContext;
+
namespace WebKit {
class WebBackForwardListItem;
class WebPageProxy;
+struct ViewSnapshot {
+#if PLATFORM(MAC)
+ RefPtr<WebCore::IOSurface> surface;
+#endif
+#if PLATFORM(IOS)
+ uint32_t slotID = 0;
+#endif
+
+ std::chrono::steady_clock::time_point creationTime;
+ uint64_t renderTreeSize;
+ float deviceScaleFactor;
+ size_t imageSizeInBytes = 0;
+
+ void clearImage();
+ bool hasImage() const;
+};
+
class ViewSnapshotStore {
WTF_MAKE_NONCOPYABLE(ViewSnapshotStore);
public:
static ViewSnapshotStore& shared();
- struct Snapshot {
-#if USE(IOSURFACE)
- RefPtr<WebCore::IOSurface> surface;
-#else
- RetainPtr<CGImageRef> image;
-#endif
-
- std::chrono::steady_clock::time_point creationTime;
- uint64_t renderTreeSize;
- float deviceScaleFactor;
-
- void clearImage();
- bool hasImage() const;
- };
-
void recordSnapshot(WebPageProxy&);
- bool getSnapshot(WebBackForwardListItem*, Snapshot&);
+ bool getSnapshot(WebBackForwardListItem*, ViewSnapshot&);
void disableSnapshotting() { m_enabled = false; }
void enableSnapshotting() { m_enabled = true; }
+ void discardSnapshots();
+
+#if PLATFORM(IOS)
+ static CAContext *snapshottingContext();
+#endif
+
private:
void pruneSnapshots(WebPageProxy&);
+ void removeSnapshotImage(ViewSnapshot&);
- HashMap<String, Snapshot> m_snapshotMap;
+ HashMap<String, ViewSnapshot> m_snapshotMap;
bool m_enabled;
- unsigned m_snapshotsWithImagesCount;
+ size_t m_snapshotCacheSize;
};
} // namespace WebKit
#import <WebCore/IOSurface.h>
#import <WebCore/UUID.h>
+#if PLATFORM(IOS)
+#import <QuartzCore/QuartzCorePrivate.h>
+#endif
+
using namespace WebCore;
-static const int maximumSnapshotCount = 20;
+#if PLATFORM(MAC)
+static const size_t maximumSnapshotCacheSize = 400 * (1024 * 1024);
+#elif PLATFORM(IOS)
+// Because snapshots are not purgeable, we should keep fewer around.
+static const size_t maximumSnapshotCacheSize = 50 * (1024 * 1024);
+#endif
namespace WebKit {
ViewSnapshotStore::ViewSnapshotStore()
: m_enabled(true)
- , m_snapshotsWithImagesCount(0)
+ , m_snapshotCacheSize(0)
{
}
ViewSnapshotStore::~ViewSnapshotStore()
{
+ discardSnapshots();
}
ViewSnapshotStore& ViewSnapshotStore::shared()
return store;
}
+#if PLATFORM(IOS)
+CAContext *ViewSnapshotStore::snapshottingContext()
+{
+ static CAContext *context;
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ NSDictionary *options = @{
+ kCAContextDisplayName: @"WebKitSnapshotting",
+ kCAContextIgnoresHitTest: @YES,
+ kCAContextDisplayId : @20000
+ };
+ context = [[CAContext remoteContextWithOptions:options] retain];
+ });
+
+ return context;
+}
+#endif
+
+void ViewSnapshotStore::removeSnapshotImage(ViewSnapshot& snapshot)
+{
+ if (!snapshot.hasImage())
+ return;
+
+ m_snapshotCacheSize -= snapshot.imageSizeInBytes;
+ snapshot.clearImage();
+}
+
void ViewSnapshotStore::pruneSnapshots(WebPageProxy& webPageProxy)
{
- if (m_snapshotsWithImagesCount <= maximumSnapshotCount)
+ if (m_snapshotCacheSize <= maximumSnapshotCacheSize)
return;
uint32_t currentIndex = webPageProxy.backForwardList().currentIndex();
}
if (mostDistantSnapshotIter != m_snapshotMap.end()) {
- mostDistantSnapshotIter->value.clearImage();
- m_snapshotsWithImagesCount--;
+ removeSnapshotImage(mostDistantSnapshotIter->value);
return;
}
}
const auto& snapshotIter = m_snapshotMap.find(oldestSnapshotUUID);
- snapshotIter->value.clearImage();
- m_snapshotsWithImagesCount--;
-}
-
-#if USE(IOSURFACE)
-static RefPtr<IOSurface> createIOSurfaceFromImage(CGImageRef image)
-{
- size_t width = CGImageGetWidth(image);
- size_t height = CGImageGetHeight(image);
-
- RefPtr<IOSurface> surface = IOSurface::create(IntSize(width, height), ColorSpaceDeviceRGB);
- RetainPtr<CGContextRef> surfaceContext = surface->ensurePlatformContext();
- CGContextDrawImage(surfaceContext.get(), CGRectMake(0, 0, width, height), image);
- CGContextFlush(surfaceContext.get());
-
- return surface;
+ removeSnapshotImage(snapshotIter->value);
}
-#endif
void ViewSnapshotStore::recordSnapshot(WebPageProxy& webPageProxy)
{
if (!item)
return;
- RetainPtr<CGImageRef> snapshotImage = webPageProxy.takeViewSnapshot();
- if (!snapshotImage)
- return;
-
pruneSnapshots(webPageProxy);
String oldSnapshotUUID = item->snapshotUUID();
if (!oldSnapshotUUID.isEmpty()) {
const auto& oldSnapshotIter = m_snapshotMap.find(oldSnapshotUUID);
if (oldSnapshotIter != m_snapshotMap.end()) {
- if (oldSnapshotIter->value.hasImage())
- m_snapshotsWithImagesCount--;
+ removeSnapshotImage(oldSnapshotIter->value);
m_snapshotMap.remove(oldSnapshotIter);
}
}
item->setSnapshotUUID(createCanonicalUUIDString());
-
- Snapshot snapshot;
+
+ ViewSnapshot snapshot = webPageProxy.takeViewSnapshot();
snapshot.creationTime = std::chrono::steady_clock::now();
snapshot.renderTreeSize = webPageProxy.renderTreeSize();
snapshot.deviceScaleFactor = webPageProxy.deviceScaleFactor();
-#if USE(IOSURFACE)
- snapshot.surface = createIOSurfaceFromImage(snapshotImage.get());
- snapshot.surface->setIsVolatile(true);
-#else
- snapshot.image = snapshotImage;
-#endif
-
m_snapshotMap.add(item->snapshotUUID(), snapshot);
-
- if (snapshot.hasImage())
- m_snapshotsWithImagesCount++;
+ m_snapshotCacheSize += snapshot.imageSizeInBytes;
}
-bool ViewSnapshotStore::getSnapshot(WebBackForwardListItem* item, ViewSnapshotStore::Snapshot& snapshot)
+bool ViewSnapshotStore::getSnapshot(WebBackForwardListItem* item, ViewSnapshot& snapshot)
{
if (item->snapshotUUID().isEmpty())
return false;
return true;
}
-void ViewSnapshotStore::Snapshot::clearImage()
+void ViewSnapshotStore::discardSnapshots()
{
-#if USE(IOSURFACE)
- surface = nullptr;
-#else
- image = nullptr;
-#endif
+ for (auto& snapshot : m_snapshotMap.values())
+ removeSnapshotImage(snapshot);
}
-bool ViewSnapshotStore::Snapshot::hasImage() const
+bool ViewSnapshot::hasImage() const
{
-#if USE(IOSURFACE)
- return surface;
-#else
- return image;
+ return imageSizeInBytes;
+}
+
+void ViewSnapshot::clearImage()
+{
+#if PLATFORM(MAC)
+ surface = nullptr;
+#elif PLATFORM(IOS)
+ if (slotID)
+ [ViewSnapshotStore::snapshottingContext() deleteSlot:slotID];
+ slotID = 0;
#endif
+ imageSizeInBytes = 0;
}
} // namespace WebKit
#import "WKBrowsingContextControllerInternal.h"
#import "WKBrowsingContextControllerInternal.h"
#import "WebKitSystemInterface.h"
+#import "WebMemoryPressureHandlerIOS.h"
#import "WebPageGroup.h"
#import "WebProcessCreationParameters.h"
#import "WebProcessMessages.h"
#import "WindowServerConnection.h"
-#if !PLATFORM(IOS)
-#import <QuartzCore/CARemoteLayerServer.h>
-#endif
#import <WebCore/Color.h>
#import <WebCore/FileSystem.h>
#import <WebCore/NotImplemented.h>
#import "NetworkProcessProxy.h"
#endif
+#if !PLATFORM(IOS)
+#import <QuartzCore/CARemoteLayerServer.h>
+#endif
+
#if PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
#if __has_include(<CFNetwork/CFURLProtocolPriv.h>)
{
registerUserDefaultsIfNeeded();
registerNotificationObservers();
+
+#if PLATFORM(IOS)
+ WebKit::WebMemoryPressureHandler::shared();
+#endif
}
String WebContext::platformDefaultApplicationCacheDirectory() const
2D2ADF0916362DD500197E47 /* PDFPluginTextAnnotation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2D2ADF0616362DC700197E47 /* PDFPluginTextAnnotation.mm */; };
2D2ADF0B16362DDB00197E47 /* PDFPluginAnnotation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2D2ADF031636243500197E47 /* PDFPluginAnnotation.mm */; };
2D2ADF1016364D8200197E47 /* PDFPluginChoiceAnnotation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2D2ADF0E16364D8200197E47 /* PDFPluginChoiceAnnotation.mm */; };
+ 2D3EF4421917646300034184 /* WebMemoryPressureHandlerIOS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2D3EF4401917646300034184 /* WebMemoryPressureHandlerIOS.cpp */; };
+ 2D3EF4431917646300034184 /* WebMemoryPressureHandlerIOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D3EF4411917646300034184 /* WebMemoryPressureHandlerIOS.h */; };
2D429BFD1721E2C700EC681F /* PDFPluginPasswordField.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2D429BFB1721E2BA00EC681F /* PDFPluginPasswordField.mm */; };
2D47B56C1810714E003A3AEE /* RemoteLayerBackingStore.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2D47B56A1810714E003A3AEE /* RemoteLayerBackingStore.mm */; };
2D47B56D1810714E003A3AEE /* RemoteLayerBackingStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D47B56B1810714E003A3AEE /* RemoteLayerBackingStore.h */; };
2D2ADF0C16363DEC00197E47 /* PDFLayerControllerDetails.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PDFLayerControllerDetails.h; path = PDF/PDFLayerControllerDetails.h; sourceTree = "<group>"; };
2D2ADF0D16364D8200197E47 /* PDFPluginChoiceAnnotation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PDFPluginChoiceAnnotation.h; path = PDF/PDFPluginChoiceAnnotation.h; sourceTree = "<group>"; };
2D2ADF0E16364D8200197E47 /* PDFPluginChoiceAnnotation.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = PDFPluginChoiceAnnotation.mm; path = PDF/PDFPluginChoiceAnnotation.mm; sourceTree = "<group>"; };
+ 2D3EF4401917646300034184 /* WebMemoryPressureHandlerIOS.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WebMemoryPressureHandlerIOS.cpp; path = ios/WebMemoryPressureHandlerIOS.cpp; sourceTree = "<group>"; };
+ 2D3EF4411917646300034184 /* WebMemoryPressureHandlerIOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WebMemoryPressureHandlerIOS.h; path = ios/WebMemoryPressureHandlerIOS.h; sourceTree = "<group>"; };
2D429BFA1721E2BA00EC681F /* PDFPluginPasswordField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PDFPluginPasswordField.h; path = PDF/PDFPluginPasswordField.h; sourceTree = "<group>"; };
2D429BFB1721E2BA00EC681F /* PDFPluginPasswordField.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = PDFPluginPasswordField.mm; path = PDF/PDFPluginPasswordField.mm; sourceTree = "<group>"; };
2D47B56A1810714E003A3AEE /* RemoteLayerBackingStore.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RemoteLayerBackingStore.mm; sourceTree = "<group>"; };
2DAF06D518BD1A470081CEB1 /* SmartMagnificationController.mm */,
2DAF06D818BD23BA0081CEB1 /* SmartMagnificationController.messages.in */,
2DA944AA1884E9BA00ED86DB /* WebInspectorProxyIOS.mm */,
+ 2D3EF4401917646300034184 /* WebMemoryPressureHandlerIOS.cpp */,
+ 2D3EF4411917646300034184 /* WebMemoryPressureHandlerIOS.h */,
2DA944AB1884E9BA00ED86DB /* WebPageProxyIOS.mm */,
2DA944AC1884E9BA00ED86DB /* WebProcessProxyIOS.mm */,
3F889D12188778C900FEADAF /* WebVideoFullscreenManagerProxy.mm */,
514D9F5719119D35000063A7 /* ServicesController.h in Headers */,
CDC3830C17212282008A2FC3 /* CookieStorageShimLibrary.h in Headers */,
515E7730184015800007203F /* UniqueIDBDatabase.h in Headers */,
+ 2D3EF4431917646300034184 /* WebMemoryPressureHandlerIOS.h in Headers */,
B878B615133428DC006888E9 /* CorrectionPanel.h in Headers */,
2989A414167D184B004F96D2 /* CustomProtocolManager.h in Headers */,
371B32DE184D67490013E2B2 /* WKNSURLProtectionSpace.h in Headers */,
BC1BE1F312D54DBD0004A228 /* WebGeolocationProvider.cpp in Sources */,
7801C099142290C400FAF9AF /* WebHitTestResult.cpp in Sources */,
2684055218B86ED60022C38B /* ViewUpdateDispatcherMessageReceiver.cpp in Sources */,
+ 2D3EF4421917646300034184 /* WebMemoryPressureHandlerIOS.cpp in Sources */,
511B24AA132E097200065A0C /* WebIconDatabase.cpp in Sources */,
51834592134532E90092B696 /* WebIconDatabaseClient.cpp in Sources */,
51D02F64132EC5B900BEAA96 /* WebIconDatabaseMessageReceiver.cpp in Sources */,