- Revision
- 273283
- Author
- [email protected]
- Date
- 2021-02-22 15:19:21 -0800 (Mon, 22 Feb 2021)
Log Message
[Cocoa] Add WKWebView session restoration API
https://bugs.webkit.org/show_bug.cgi?id=220958
<rdar://70956146>
Reviewed by Geoffrey Garen.
Source/WebKit:
Add WKWebView session restoration API so that applications can easily retrieve
view state (such as back-forward list, scroll position, form data...) and
restore it on a WKWebView later on.
* UIProcess/API/Cocoa/WKWebView.h:
* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView interactionState]):
(-[WKWebView setInteractionState:]):
Tools:
Add API test coverage.
* TestWebKitAPI/Tests/WebKit/WKBackForwardList.mm:
(TEST):
Modified Paths
Diff
Modified: trunk/Source/WebKit/ChangeLog (273282 => 273283)
--- trunk/Source/WebKit/ChangeLog 2021-02-22 23:07:20 UTC (rev 273282)
+++ trunk/Source/WebKit/ChangeLog 2021-02-22 23:19:21 UTC (rev 273283)
@@ -1,5 +1,22 @@
2021-02-22 Chris Dumez <[email protected]>
+ [Cocoa] Add WKWebView session restoration API
+ https://bugs.webkit.org/show_bug.cgi?id=220958
+ <rdar://70956146>
+
+ Reviewed by Geoffrey Garen.
+
+ Add WKWebView session restoration API so that applications can easily retrieve
+ view state (such as back-forward list, scroll position, form data...) and
+ restore it on a WKWebView later on.
+
+ * UIProcess/API/Cocoa/WKWebView.h:
+ * UIProcess/API/Cocoa/WKWebView.mm:
+ (-[WKWebView interactionState]):
+ (-[WKWebView setInteractionState:]):
+
+2021-02-22 Chris Dumez <[email protected]>
+
Use adoptNS() as soon as we [[ObjcClass alloc] init] to avoid leaks
https://bugs.webkit.org/show_bug.cgi?id=222237
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.h (273282 => 273283)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.h 2021-02-22 23:07:20 UTC (rev 273282)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.h 2021-02-22 23:19:21 UTC (rev 273283)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014-2020 Apple Inc. All rights reserved.
+ * Copyright (C) 2014-2021 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -473,6 +473,12 @@
*/
@property (nonatomic, nullable, copy) NSString *mediaType WK_API_AVAILABLE(macos(11.0), ios(14.0));
+/* @abstract The interaction state for the WKWebView
+ @discussion The interaction state (back-forward list, currently loaded page, scroll position, form data...) for the WKWebView, which
+ can be retrieved and set on another WKWebView to restore state.
+*/
+@property (nonatomic, nullable, copy) id interactionState WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
+
#if !TARGET_OS_IPHONE
/* @abstract Returns an NSPrintOperation object configured to print the contents of this WKWebView
@param printInfo The print info object used to configure the resulting print operation.
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm (273282 => 273283)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm 2021-02-22 23:07:20 UTC (rev 273282)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm 2021-02-22 23:19:21 UTC (rev 273283)
@@ -52,6 +52,7 @@
#import "RemoteObjectRegistryMessages.h"
#import "ResourceLoadDelegate.h"
#import "SafeBrowsingWarning.h"
+#import "SessionStateCoding.h"
#import "SharedBufferCopy.h"
#import "UIDelegate.h"
#import "VideoFullscreenManagerProxy.h"
@@ -1235,6 +1236,22 @@
return _page->overriddenMediaType().isNull() ? nil : (NSString *)_page->overriddenMediaType();
}
+- (id)interactionState
+{
+ return WebKit::encodeSessionState(_page->sessionState()).autorelease();
+}
+
+- (void)setInteractionState:(id)interactionState
+{
+ if (![(id)interactionState isKindOfClass:[NSData class]])
+ return;
+
+ WebKit::SessionState sessionState;
+ if (!WebKit::decodeSessionState((NSData *)(interactionState), sessionState))
+ return;
+ _page->restoreFromSessionState(sessionState, true);
+}
+
#pragma mark - iOS API
#if PLATFORM(IOS_FAMILY)
Modified: trunk/Tools/ChangeLog (273282 => 273283)
--- trunk/Tools/ChangeLog 2021-02-22 23:07:20 UTC (rev 273282)
+++ trunk/Tools/ChangeLog 2021-02-22 23:19:21 UTC (rev 273283)
@@ -1,5 +1,18 @@
2021-02-22 Chris Dumez <[email protected]>
+ [Cocoa] Add WKWebView session restoration API
+ https://bugs.webkit.org/show_bug.cgi?id=220958
+ <rdar://70956146>
+
+ Reviewed by Geoffrey Garen.
+
+ Add API test coverage.
+
+ * TestWebKitAPI/Tests/WebKit/WKBackForwardList.mm:
+ (TEST):
+
+2021-02-22 Chris Dumez <[email protected]>
+
Use adoptNS() as soon as we [[ObjcClass alloc] init] to avoid leaks
https://bugs.webkit.org/show_bug.cgi?id=222237
Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit/WKBackForwardList.mm (273282 => 273283)
--- trunk/Tools/TestWebKitAPI/Tests/WebKit/WKBackForwardList.mm 2021-02-22 23:07:20 UTC (rev 273282)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit/WKBackForwardList.mm 2021-02-22 23:19:21 UTC (rev 273283)
@@ -166,3 +166,146 @@
TestWebKitAPI::Util::run(&done);
EXPECT_STREQ(webView.get().backForwardList.currentItem.URL.absoluteString.UTF8String, simple.absoluteString.UTF8String);
}
+
+TEST(WKBackForwardList, InteractionStateRestoration)
+{
+ auto webView = adoptNS([[WKWebView alloc] init]);
+
+ NSURL *url1 = [[NSBundle mainBundle] URLForResource:@"simple" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
+ NSURL *url2 = [[NSBundle mainBundle] URLForResource:@"simple2" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
+ NSURL *url3 = [[NSBundle mainBundle] URLForResource:@"simple3" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
+
+ [webView loadRequest:[NSURLRequest requestWithURL:url1]];
+ [webView _test_waitForDidFinishNavigation];
+
+ [webView loadRequest:[NSURLRequest requestWithURL:url2]];
+ [webView _test_waitForDidFinishNavigation];
+
+ [webView loadRequest:[NSURLRequest requestWithURL:url3]];
+ [webView _test_waitForDidFinishNavigation];
+
+ WKBackForwardList *list = [webView backForwardList];
+ EXPECT_EQ((NSUInteger)2, list.backList.count);
+ EXPECT_EQ((NSUInteger)0, list.forwardList.count);
+ EXPECT_STREQ([[list.currentItem URL] absoluteString].UTF8String, url3.absoluteString.UTF8String);
+
+ id interactionState = [webView interactionState];
+ RetainPtr<NSURL> temporaryFile = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:[NSUUID UUID].UUIDString] isDirectory:NO];
+ NSError *error = nil;
+ RetainPtr<NSData> archivedInteractionState = [NSKeyedArchiver archivedDataWithRootObject:interactionState requiringSecureCoding:YES error:&error];
+ EXPECT_TRUE(!error);
+ interactionState = nil;
+ [archivedInteractionState writeToURL:temporaryFile.get() options:NSDataWritingAtomic error:&error];
+ archivedInteractionState = nil;
+ EXPECT_TRUE(!error);
+
+ webView = adoptNS([[WKWebView alloc] init]);
+
+ archivedInteractionState = [NSData dataWithContentsOfURL:temporaryFile.get()];
+ interactionState = [NSKeyedUnarchiver unarchivedObjectOfClass:[(id)[webView interactionState] class] fromData:archivedInteractionState.get() error:&error];
+ EXPECT_TRUE(!error);
+
+ [webView setInteractionState:interactionState];
+ [webView _test_waitForDidFinishNavigation];
+
+ WKBackForwardList *newList = [webView backForwardList];
+
+ EXPECT_EQ((NSUInteger)2, newList.backList.count);
+ EXPECT_EQ((NSUInteger)0, newList.forwardList.count);
+ EXPECT_STREQ([[newList.currentItem URL] absoluteString].UTF8String, url3.absoluteString.UTF8String);
+
+ done = false;
+ [webView evaluateJavaScript:@"document.body.innerText" completionHandler:^(id result, NSError *error) {
+ EXPECT_TRUE(!error);
+ NSString* bodyText = result;
+ EXPECT_WK_STREQ(@"Third simple HTML file.", bodyText);
+ done = true;
+ }];
+ TestWebKitAPI::Util::run(&done);
+
+ [webView goBack];
+ [webView _test_waitForDidFinishNavigation];
+
+ done = false;
+ [webView evaluateJavaScript:@"document.body.innerText" completionHandler:^(id result, NSError *error) {
+ EXPECT_TRUE(!error);
+ NSString* bodyText = result;
+ EXPECT_WK_STREQ(@"Second simple HTML file.", bodyText);
+ done = true;
+ }];
+ TestWebKitAPI::Util::run(&done);
+
+ [webView goBack];
+ [webView _test_waitForDidFinishNavigation];
+
+ done = false;
+ [webView evaluateJavaScript:@"document.body.innerText" completionHandler:^(id result, NSError *error) {
+ EXPECT_TRUE(!error);
+ NSString* bodyText = result;
+ EXPECT_WK_STREQ(@"Simple HTML file.", bodyText);
+ done = true;
+ }];
+ TestWebKitAPI::Util::run(&done);
+}
+
+TEST(WKBackForwardList, InteractionStateRestorationNil)
+{
+ auto webView = adoptNS([[WKWebView alloc] init]);
+
+ NSURL *url1 = [[NSBundle mainBundle] URLForResource:@"simple" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
+ NSURL *url2 = [[NSBundle mainBundle] URLForResource:@"simple2" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
+ NSURL *url3 = [[NSBundle mainBundle] URLForResource:@"simple3" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
+
+ [webView loadRequest:[NSURLRequest requestWithURL:url1]];
+ [webView _test_waitForDidFinishNavigation];
+
+ [webView loadRequest:[NSURLRequest requestWithURL:url2]];
+ [webView _test_waitForDidFinishNavigation];
+
+ [webView loadRequest:[NSURLRequest requestWithURL:url3]];
+ [webView _test_waitForDidFinishNavigation];
+
+ WKBackForwardList *list = [webView backForwardList];
+ EXPECT_EQ((NSUInteger)2, list.backList.count);
+ EXPECT_EQ((NSUInteger)0, list.forwardList.count);
+ EXPECT_STREQ([[list.currentItem URL] absoluteString].UTF8String, url3.absoluteString.UTF8String);
+
+ [webView setInteractionState:nil];
+
+ list = [webView backForwardList];
+ EXPECT_EQ((NSUInteger)2, list.backList.count);
+ EXPECT_EQ((NSUInteger)0, list.forwardList.count);
+ EXPECT_STREQ([[list.currentItem URL] absoluteString].UTF8String, url3.absoluteString.UTF8String);
+}
+
+TEST(WKBackForwardList, InteractionStateRestorationInvalid)
+{
+ auto webView = adoptNS([[WKWebView alloc] init]);
+
+ NSURL *url1 = [[NSBundle mainBundle] URLForResource:@"simple" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
+ NSURL *url2 = [[NSBundle mainBundle] URLForResource:@"simple2" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
+ NSURL *url3 = [[NSBundle mainBundle] URLForResource:@"simple3" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
+
+ [webView loadRequest:[NSURLRequest requestWithURL:url1]];
+ [webView _test_waitForDidFinishNavigation];
+
+ [webView loadRequest:[NSURLRequest requestWithURL:url2]];
+ [webView _test_waitForDidFinishNavigation];
+
+ [webView loadRequest:[NSURLRequest requestWithURL:url3]];
+ [webView _test_waitForDidFinishNavigation];
+
+ WKBackForwardList *list = [webView backForwardList];
+ EXPECT_EQ((NSUInteger)2, list.backList.count);
+ EXPECT_EQ((NSUInteger)0, list.forwardList.count);
+ EXPECT_STREQ([[list.currentItem URL] absoluteString].UTF8String, url3.absoluteString.UTF8String);
+
+ NSString *invalidState = @"foo";
+ [webView setInteractionState:invalidState];
+
+ list = [webView backForwardList];
+ EXPECT_EQ((NSUInteger)2, list.backList.count);
+ EXPECT_EQ((NSUInteger)0, list.forwardList.count);
+ EXPECT_STREQ([[list.currentItem URL] absoluteString].UTF8String, url3.absoluteString.UTF8String);
+}
+