diff --git a/Source/WebCore/PAL/pal/spi/cocoa/FoundationSPI.h b/Source/WebCore/PAL/pal/spi/cocoa/FoundationSPI.h index 1f938e9bd963..162bb582911c 100644 --- a/Source/WebCore/PAL/pal/spi/cocoa/FoundationSPI.h +++ b/Source/WebCore/PAL/pal/spi/cocoa/FoundationSPI.h @@ -30,3 +30,6 @@ - (NSDictionary *)detail; @end +@interface NSHTTPURLResponse () ++ (BOOL)isErrorStatusCode:(NSInteger)statusCode; +@end diff --git a/Source/WebCore/html/HTMLAnchorElement.cpp b/Source/WebCore/html/HTMLAnchorElement.cpp index cd73aeac979f..44aa0909724a 100644 --- a/Source/WebCore/html/HTMLAnchorElement.cpp +++ b/Source/WebCore/html/HTMLAnchorElement.cpp @@ -611,6 +611,10 @@ void HTMLAnchorElement::handleClick(Event& event) systemPreviewInfo.element.webPageIdentifier = valueOrDefault(document().frame()->loader().pageID()); if (auto* child = firstElementChild()) systemPreviewInfo.previewRect = child->boundsInRootViewSpace(); + + if (auto* page = document().page()) + page->handleSystemPreview(WTFMove(completedURL), WTFMove(systemPreviewInfo)); + return; } #endif diff --git a/Source/WebCore/page/ChromeClient.h b/Source/WebCore/page/ChromeClient.h index b7b055dccce7..7d84ff206852 100644 --- a/Source/WebCore/page/ChromeClient.h +++ b/Source/WebCore/page/ChromeClient.h @@ -637,6 +637,10 @@ class ChromeClient { virtual void abortApplePayAMSUISession() { } #endif +#if USE(SYSTEM_PREVIEW) + virtual void handleSystemPreview(const URL&, const SystemPreviewInfo&) { } +#endif + virtual void requestCookieConsent(CompletionHandler&&) = 0; virtual const AtomString& searchStringForModalContainerObserver() const { return nullAtom(); } diff --git a/Source/WebCore/page/Page.cpp b/Source/WebCore/page/Page.cpp index 15ea4cda28d7..c13f2d338f4e 100644 --- a/Source/WebCore/page/Page.cpp +++ b/Source/WebCore/page/Page.cpp @@ -3903,6 +3903,13 @@ void Page::abortApplePayAMSUISession(ApplePayAMSUIPaymentHandler& paymentHandler #endif // ENABLE(APPLE_PAY_AMS_UI) +#if USE(SYSTEM_PREVIEW) +void Page::handleSystemPreview(const URL& url, const SystemPreviewInfo& systemPreviewInfo) +{ + chrome().client().handleSystemPreview(url, systemPreviewInfo); +} +#endif + #if ENABLE(MEDIA_SESSION_COORDINATOR) void Page::setMediaSessionCoordinator(Ref&& mediaSessionCoordinator) { diff --git a/Source/WebCore/page/Page.h b/Source/WebCore/page/Page.h index ed6ccc749bd7..234246aa85c5 100644 --- a/Source/WebCore/page/Page.h +++ b/Source/WebCore/page/Page.h @@ -601,6 +601,10 @@ class Page : public Supplementable, public CanMakeWeakPtr { void abortApplePayAMSUISession(ApplePayAMSUIPaymentHandler&); #endif +#if USE(SYSTEM_PREVIEW) + void handleSystemPreview(const URL&, const SystemPreviewInfo&); +#endif + #if ENABLE(WEB_AUTHN) AuthenticatorCoordinator& authenticatorCoordinator() { return m_authenticatorCoordinator.get(); } #endif diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivateForTesting.h b/Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivateForTesting.h index fe005241877d..0a5392ff5713 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivateForTesting.h +++ b/Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivateForTesting.h @@ -136,6 +136,8 @@ struct WKAppPrivacyReportTestingData { - (void)_setConnectedToHardwareConsoleForTesting:(BOOL)connected; +- (void)_setSystemPreviewCompletionHandlerForLoadTesting:(void(^)(bool))completionHandler; + @end typedef NS_ENUM(NSInteger, _WKMediaSessionReadyState) { diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKWebViewTesting.mm b/Source/WebKit/UIProcess/API/Cocoa/WKWebViewTesting.mm index 15e0e2434e46..558851c716a1 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/WKWebViewTesting.mm +++ b/Source/WebKit/UIProcess/API/Cocoa/WKWebViewTesting.mm @@ -577,6 +577,13 @@ - (void)_setConnectedToHardwareConsoleForTesting:(BOOL)connected #endif } +- (void)_setSystemPreviewCompletionHandlerForLoadTesting:(void(^)(bool))completionHandler +{ +#if USE(SYSTEM_PREVIEW) + _page->setSystemPreviewCompletionHandlerForLoadTesting(makeBlockPtr(completionHandler)); +#endif +} + - (void)_createMediaSessionCoordinatorForTesting:(id <_WKMediaSessionCoordinator>)privateCoordinator completionHandler:(void(^)(BOOL))completionHandler { #if ENABLE(MEDIA_SESSION_COORDINATOR) diff --git a/Source/WebKit/UIProcess/Cocoa/SystemPreviewControllerCocoa.mm b/Source/WebKit/UIProcess/Cocoa/SystemPreviewControllerCocoa.mm index 8184d825e578..a8fd98ac4ed2 100644 --- a/Source/WebKit/UIProcess/Cocoa/SystemPreviewControllerCocoa.mm +++ b/Source/WebKit/UIProcess/Cocoa/SystemPreviewControllerCocoa.mm @@ -31,12 +31,15 @@ #import "APIUIClient.h" #import "WebPageProxy.h" #import "WebProcessProxy.h" +#import "_WKDataTaskDelegate.h" +#import "_WKDataTaskInternal.h" #import #import #import #import #import #import +#import #import #import @@ -253,8 +256,202 @@ - (UIImage *)previewController:(QLPreviewController *)controller transitionImage @end +@interface _WKSystemPreviewDataTaskDelegate : NSObject <_WKDataTaskDelegate> { + WebKit::SystemPreviewController* _previewController; + long long _expectedContentLength; + RetainPtr _data; + RetainPtr _suggestedFilename; +}; +@end + +@implementation _WKSystemPreviewDataTaskDelegate + +- (id)initWithSystemPreviewController:(WebKit::SystemPreviewController*)previewController +{ + if (!(self = [super init])) + return nil; + + _previewController = previewController; + return self; +} + +- (BOOL)isValidMIMEType:(NSString *)MIMEType +{ + return WebCore::MIMETypeRegistry::isUSDMIMEType(MIMEType); +} + +- (void)dataTask:(_WKDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response decisionHandler:(void (^)(_WKDataTaskResponsePolicy))decisionHandler +{ + if ([response isKindOfClass:[NSHTTPURLResponse class]]) { + NSHTTPURLResponse *HTTPResponse = (NSHTTPURLResponse *)response; + if ([NSHTTPURLResponse isErrorStatusCode:HTTPResponse.statusCode]) { + RELEASE_LOG(SystemPreview, "cancelling subresource load due to error status code: %ld", (long)HTTPResponse.statusCode); + decisionHandler(_WKDataTaskResponsePolicyCancel); + _previewController->loadFailed(); + return; + } + } + + if (![self isValidMIMEType:response.MIMEType]) { + RELEASE_LOG(SystemPreview, "cancelling subresource load due to unhandled MIME type: \"%@\"", response.MIMEType); + decisionHandler(_WKDataTaskResponsePolicyCancel); + _previewController->loadFailed(); + return; + } + + _expectedContentLength = response.expectedContentLength; + if (_expectedContentLength == NSURLResponseUnknownLength) + _expectedContentLength = 0; + + _data = adoptNS([[NSMutableData alloc] initWithCapacity:_expectedContentLength]); + _suggestedFilename = adoptNS([response.suggestedFilename copy]); + decisionHandler(_WKDataTaskResponsePolicyAllow); +} + +- (void)dataTask:(_WKDataTask *)dataTask didReceiveData:(NSData *)data +{ + ASSERT(_data); + [_data appendData:data]; + if (_expectedContentLength) + _previewController->updateProgress((float)_data.get().length / _expectedContentLength); +} + +- (void)dataTask:(_WKDataTask *)dataTask didCompleteWithError:(NSError *)error +{ + if (error) { + _previewController->loadFailed(); + return; + } + + [self completeLoad]; +} + +- (void)completeLoad +{ + FileSystem::PlatformFileHandle fileHandle; + auto filePath = FileSystem::openTemporaryFile("SystemPreview"_s, fileHandle, ".usdz"_s); + ASSERT(FileSystem::isHandleValid(fileHandle)); + + size_t byteCount = FileSystem::writeToFile(fileHandle, [_data bytes], [_data length]); + FileSystem::closeFile(fileHandle); + + if (byteCount != _data.get().length) { + _previewController->loadFailed(); + return; + } + + _previewController->loadCompleted(URL::fileURLWithFileSystemPath(filePath)); +} + +@end + namespace WebKit { +void SystemPreviewController::begin(const URL& url, const WebCore::SystemPreviewInfo& systemPreviewInfo) +{ + ASSERT(!m_qlPreviewController); + if (m_qlPreviewController) + return; + + UIViewController *presentingViewController = m_webPageProxy.uiClient().presentingViewController(); + + if (!presentingViewController) + return; + + m_systemPreviewInfo = systemPreviewInfo; + + RELEASE_LOG(SystemPreview, "SystemPreview began on %lld", m_systemPreviewInfo.element.elementIdentifier.toUInt64()); + + auto request = WebCore::ResourceRequest(url); + WeakPtr weakThis { *this }; + m_webPageProxy.dataTaskWithRequest(WTFMove(request), [weakThis] (Ref&& task) { + if (!weakThis) + return; + + auto strongThis = weakThis.get(); + + _WKDataTask *dataTask = wrapper(task); + strongThis->m_wkSystemPreviewDataTaskDelegate = adoptNS([[_WKSystemPreviewDataTaskDelegate alloc] initWithSystemPreviewController:strongThis]); + [dataTask setDelegate:strongThis->m_wkSystemPreviewDataTaskDelegate.get()]; + strongThis->takeActivityToken(); + }); + + m_qlPreviewController = adoptNS([PAL::allocQLPreviewControllerInstance() init]); + + m_qlPreviewControllerDelegate = adoptNS([[_WKPreviewControllerDelegate alloc] initWithSystemPreviewController:this]); + [m_qlPreviewController setDelegate:m_qlPreviewControllerDelegate.get()]; + + m_qlPreviewControllerDataSource = adoptNS([[_WKPreviewControllerDataSource alloc] initWithSystemPreviewController:this MIMEType:@"model/vnd.usdz+zip" originatingPageURL:url]); + [m_qlPreviewController setDataSource:m_qlPreviewControllerDataSource.get()]; + + [presentingViewController presentViewController:m_qlPreviewController.get() animated:YES completion:nullptr]; +} + +void SystemPreviewController::loadCompleted(const URL& downloadedFile) +{ + RELEASE_LOG(SystemPreview, "SystemPreview load has finished on %lld", m_systemPreviewInfo.element.elementIdentifier.toUInt64()); + +#if HAVE(UIKIT_WEBKIT_INTERNALS) + ASSERT(equalIgnoringFragmentIdentifier(m_destinationURL, url)); + NSURL *nsurl = (NSURL *)url; + if ([getASVLaunchPreviewClass() respondsToSelector:@selector(launchPreviewApplicationWithURLs:completion:)]) + [getASVLaunchPreviewClass() launchPreviewApplicationWithURLs:@[nsurl] completion:^(NSError *error) { }]; +#else + if (m_qlPreviewControllerDataSource) + [m_qlPreviewControllerDataSource finish:downloadedFile]; +#endif + releaseActivityTokenIfNecessary(); + + if (m_testingCallback) + m_testingCallback(true); +} + +void SystemPreviewController::loadFailed() +{ + RELEASE_LOG(SystemPreview, "SystemPreview failed on %lld", m_systemPreviewInfo.element.elementIdentifier.toUInt64()); + +#if !HAVE(UIKIT_WEBKIT_INTERNALS) + if (m_qlPreviewControllerDataSource) + [m_qlPreviewControllerDataSource.get() failWithError:nil]; + + if (m_qlPreviewController) + [m_qlPreviewController.get() dismissViewControllerAnimated:YES completion:nullptr]; + + m_qlPreviewControllerDelegate = nullptr; + m_qlPreviewControllerDataSource = nullptr; + m_qlPreviewController = nullptr; + m_wkSystemPreviewDataTaskDelegate = nullptr; +#endif + releaseActivityTokenIfNecessary(); + + if (m_testingCallback) + m_testingCallback(false); +} + +void SystemPreviewController::takeActivityToken() +{ +#if USE(RUNNINGBOARD) + RELEASE_LOG(ProcessSuspension, "%p - UIProcess is taking a background assertion because it is downloading a system preview", this); + ASSERT(!m_activity); + m_activity = page().process().throttler().backgroundActivity("System preview download"_s).moveToUniquePtr(); +#endif +} + +void SystemPreviewController::releaseActivityTokenIfNecessary() +{ +#if USE(RUNNINGBOARD) + if (m_activity) { + RELEASE_LOG(ProcessSuspension, "%p UIProcess is releasing a background assertion because a system preview download completed", this); + m_activity = nullptr; + } +#endif +} + +void SystemPreviewController::setCompletionHandlerForLoadTesting(CompletionHandler&& handler) +{ + m_testingCallback = WTFMove(handler); +} + void SystemPreviewController::start(URL originatingPageURL, const String& mimeType, const WebCore::SystemPreviewInfo& systemPreviewInfo) { #if HAVE(UIKIT_WEBKIT_INTERNALS) @@ -285,7 +482,7 @@ - (UIImage *)previewController:(QLPreviewController *)controller transitionImage m_originatingPageURL = originatingPageURL; - RELEASE_LOG(SystemPreview, "SystemPreview began on %lld", m_systemPreviewInfo.element.elementIdentifier.toUInt64()); + RELEASE_LOG(SystemPreview, "SystemPreview started on %lld", m_systemPreviewInfo.element.elementIdentifier.toUInt64()); } void SystemPreviewController::setDestinationURL(URL url) diff --git a/Source/WebKit/UIProcess/SystemPreviewController.h b/Source/WebKit/UIProcess/SystemPreviewController.h index 392e5a42d639..e53015081501 100644 --- a/Source/WebKit/UIProcess/SystemPreviewController.h +++ b/Source/WebKit/UIProcess/SystemPreviewController.h @@ -27,30 +27,40 @@ #if USE(SYSTEM_PREVIEW) +#include "ProcessThrottler.h" #include #include #include #include #include +#include OBJC_CLASS NSString; #if USE(QUICK_LOOK) OBJC_CLASS QLPreviewController; OBJC_CLASS _WKPreviewControllerDataSource; OBJC_CLASS _WKPreviewControllerDelegate; +OBJC_CLASS _WKSystemPreviewDataTaskDelegate; #endif namespace WebKit { class WebPageProxy; -class SystemPreviewController { +class SystemPreviewController : public CanMakeWeakPtr { WTF_MAKE_FAST_ALLOCATED; public: explicit SystemPreviewController(WebPageProxy&); bool canPreview(const String& mimeType) const; + // New methods that use WKDataTask. + void begin(const URL&, const WebCore::SystemPreviewInfo&); + void loadCompleted(const URL& downloadedFile); + void loadFailed(); + void end(); + + // Old methods that use LegacyDownloadClient. void start(URL originatingPageURL, const String& mimeType, const WebCore::SystemPreviewInfo&); void setDestinationURL(URL); void updateProgress(float); @@ -64,8 +74,13 @@ class SystemPreviewController { void triggerSystemPreviewAction(); void triggerSystemPreviewActionWithTargetForTesting(uint64_t elementID, NSString* documentID, uint64_t pageID); + void setCompletionHandlerForLoadTesting(CompletionHandler&&); private: + + void takeActivityToken(); + void releaseActivityTokenIfNecessary(); + WebPageProxy& m_webPageProxy; WebCore::SystemPreviewInfo m_systemPreviewInfo; URL m_destinationURL; @@ -74,7 +89,12 @@ class SystemPreviewController { RetainPtr m_qlPreviewController; RetainPtr<_WKPreviewControllerDelegate> m_qlPreviewControllerDelegate; RetainPtr<_WKPreviewControllerDataSource> m_qlPreviewControllerDataSource; + RetainPtr<_WKSystemPreviewDataTaskDelegate> m_wkSystemPreviewDataTaskDelegate; #endif + + std::unique_ptr m_activity; + CompletionHandler m_testingCallback; + }; } diff --git a/Source/WebKit/UIProcess/WebPageProxy.cpp b/Source/WebKit/UIProcess/WebPageProxy.cpp index 4b0c55ba4c10..3f3837c6e72d 100644 --- a/Source/WebKit/UIProcess/WebPageProxy.cpp +++ b/Source/WebKit/UIProcess/WebPageProxy.cpp @@ -12570,6 +12570,20 @@ FloatSize WebPageProxy::viewportSizeForCSSViewportUnits() const return valueOrDefault(internals().viewportSizeForCSSViewportUnits); } +#if USE(SYSTEM_PREVIEW) +void WebPageProxy::handleSystemPreview(const URL& url, const SystemPreviewInfo& systemPreviewInfo) +{ + if (m_systemPreviewController) + m_systemPreviewController->begin(url, systemPreviewInfo); +} + +void WebPageProxy::setSystemPreviewCompletionHandlerForLoadTesting(CompletionHandler&& handler) +{ + if (m_systemPreviewController) + m_systemPreviewController->setCompletionHandlerForLoadTesting(WTFMove(handler)); +} +#endif + } // namespace WebKit #undef WEBPAGEPROXY_RELEASE_LOG diff --git a/Source/WebKit/UIProcess/WebPageProxy.h b/Source/WebKit/UIProcess/WebPageProxy.h index 857e91de62ab..21fba9fea976 100644 --- a/Source/WebKit/UIProcess/WebPageProxy.h +++ b/Source/WebKit/UIProcess/WebPageProxy.h @@ -2156,6 +2156,11 @@ class WebPageProxy final : public API::ObjectImpl, publ void clearNotifications(const Vector& notificationIDs); void didDestroyNotification(const UUID& notificationID); +#if USE(SYSTEM_PREVIEW) + void handleSystemPreview(const URL&, const WebCore::SystemPreviewInfo&); + void setSystemPreviewCompletionHandlerForLoadTesting(CompletionHandler&&); +#endif + void requestCookieConsent(CompletionHandler&&); void classifyModalContainerControls(Vector&& texts, CompletionHandler&&)>&&); void decidePolicyForModalContainer(OptionSet, CompletionHandler&&); diff --git a/Source/WebKit/UIProcess/WebPageProxy.messages.in b/Source/WebKit/UIProcess/WebPageProxy.messages.in index 90902fe48311..facc1412db39 100644 --- a/Source/WebKit/UIProcess/WebPageProxy.messages.in +++ b/Source/WebKit/UIProcess/WebPageProxy.messages.in @@ -623,6 +623,10 @@ messages -> WebPageProxy { AbortApplePayAMSUISession() #endif +#if USE(SYSTEM_PREVIEW) + HandleSystemPreview(URL url, struct WebCore::SystemPreviewInfo systemPreviewInfo) +#endif + RequestCookieConsent() -> (enum:uint8_t WebCore::CookieConsentDecisionResult result) ClassifyModalContainerControls(Vector texts) -> (Vector types) DecidePolicyForModalContainer(OptionSet types) -> (enum:uint8_t WebCore::ModalContainerDecision decision) diff --git a/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp b/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp index cee4ba1e4263..298a86891be5 100644 --- a/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp +++ b/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp @@ -1682,6 +1682,13 @@ void WebChromeClient::abortApplePayAMSUISession() #endif // ENABLE(APPLE_PAY_AMS_UI) +#if USE(SYSTEM_PREVIEW) +void WebChromeClient::handleSystemPreview(const URL& url, const SystemPreviewInfo& systemPreviewInfo) +{ + m_page.send(Messages::WebPageProxy::HandleSystemPreview(WTFMove(url), WTFMove(systemPreviewInfo))); +} +#endif + void WebChromeClient::requestCookieConsent(CompletionHandler&& completion) { m_page.sendWithAsyncReply(Messages::WebPageProxy::RequestCookieConsent(), WTFMove(completion)); diff --git a/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h b/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h index b1f3862fb09f..f1c0cbddb3fb 100644 --- a/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h +++ b/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h @@ -479,6 +479,10 @@ class WebChromeClient final : public WebCore::ChromeClient { void abortApplePayAMSUISession() final; #endif +#if USE(SYSTEM_PREVIEW) + void handleSystemPreview(const URL&, const WebCore::SystemPreviewInfo&) final; +#endif + void requestCookieConsent(CompletionHandler&&) final; void classifyModalContainerControls(Vector&&, CompletionHandler&&)>&&) final; diff --git a/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj b/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj index 24fc1ff1b6cd..d269a8e4b6e2 100644 --- a/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj +++ b/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj @@ -192,6 +192,8 @@ 3128A81323763FAC00D90D40 /* link-with-image.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 3128A81223763F0B00D90D40 /* link-with-image.html */; }; 3128A8152376413300D90D40 /* image.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 3128A814237640FD00D90D40 /* image.html */; }; 313C3A0221E567C300DBA86E /* SystemPreviewBlobNaming.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 313C3A0121E5677A00DBA86E /* SystemPreviewBlobNaming.html */; }; + 31727A5329F7518C00A7FB0F /* system-preview.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 31727A4A29F7338C00A7FB0F /* system-preview.html */; }; + 31727A5429F7519400A7FB0F /* UnitBox.usdz in Copy Resources */ = {isa = PBXBuildFile; fileRef = 31727A5229F733D300A7FB0F /* UnitBox.usdz */; }; 31903C912765077400363472 /* color-scheme.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 31903C902764FE1400363472 /* color-scheme.html */; }; 31B76E4523299BDC007FED2C /* system-preview-trigger.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 31B76E4423299BA3007FED2C /* system-preview-trigger.html */; }; 31E9BDA1247F4C62002E51A2 /* WebGLPrepareDisplayOnWebThread.mm in Sources */ = {isa = PBXBuildFile; fileRef = 31E9BDA0247F4C62002E51A2 /* WebGLPrepareDisplayOnWebThread.mm */; }; @@ -1833,6 +1835,7 @@ 9BD6D3A51F7B218300BD4962 /* sunset-in-cupertino-600px.jpg in Copy Resources */, 1CC4C74D28890D3700A3B23D /* SVGFont.html in Copy Resources */, 31B76E4523299BDC007FED2C /* system-preview-trigger.html in Copy Resources */, + 31727A5329F7518C00A7FB0F /* system-preview.html in Copy Resources */, 313C3A0221E567C300DBA86E /* SystemPreviewBlobNaming.html in Copy Resources */, 51C234CF2970E13500E35C4B /* test-mse-audio.webm in Copy Resources */, CD59F53519E9110D00CF1835 /* test-mse.mp4 in Copy Resources */, @@ -1852,6 +1855,7 @@ 4952BE5F257816F800B0AEF1 /* try-text-select-with-disabled-text-interaction.html in Copy Resources */, F4451C761EB8FD890020C5DA /* two-paragraph-contenteditable.html in Copy Resources */, 1D67BFDD2433EE66006B5047 /* two-videos.html in Copy Resources */, + 31727A5429F7519400A7FB0F /* UnitBox.usdz in Copy Resources */, 1C51534C261596D700FBC4FE /* UserInstalledAhem.html in Copy Resources */, C540F784152E5A9A00A40C8C /* verboseMarkup.html in Copy Resources */, CD57779D211CE91F001B371E /* video-with-audio-and-web-audio.html in Copy Resources */, @@ -2199,6 +2203,8 @@ 3128A81223763F0B00D90D40 /* link-with-image.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "link-with-image.html"; sourceTree = ""; }; 3128A814237640FD00D90D40 /* image.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = image.html; sourceTree = ""; }; 313C3A0121E5677A00DBA86E /* SystemPreviewBlobNaming.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = SystemPreviewBlobNaming.html; sourceTree = ""; }; + 31727A4A29F7338C00A7FB0F /* system-preview.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "system-preview.html"; sourceTree = ""; }; + 31727A5229F733D300A7FB0F /* UnitBox.usdz */ = {isa = PBXFileReference; lastKnownFileType = file.usdz; path = UnitBox.usdz; sourceTree = ""; }; 31903C902764FE1400363472 /* color-scheme.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "color-scheme.html"; sourceTree = ""; }; 31B76E4223298E2B007FED2C /* SystemPreview.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SystemPreview.mm; sourceTree = ""; }; 31B76E4423299BA3007FED2C /* system-preview-trigger.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "system-preview-trigger.html"; sourceTree = ""; }; @@ -4804,6 +4810,7 @@ 9BD6D39E1F7B201E00BD4962 /* sunset-in-cupertino-600px.jpg */, 1CC4C74B28890C5400A3B23D /* SVGFont.html */, 31B76E4423299BA3007FED2C /* system-preview-trigger.html */, + 31727A4A29F7338C00A7FB0F /* system-preview.html */, 313C3A0121E5677A00DBA86E /* SystemPreviewBlobNaming.html */, F46D43AA26D7090300969E5E /* test.jpg */, 49C64FD628349C19005BF0C2 /* test.pages */, @@ -4815,6 +4822,7 @@ C22FA32C228F877A009D7988 /* TextWidth.html */, 4952BE5C2578113900B0AEF1 /* try-text-select-with-disabled-text-interaction.html */, F4451C751EB8FD7C0020C5DA /* two-paragraph-contenteditable.html */, + 31727A5229F733D300A7FB0F /* UnitBox.usdz */, CD57779B211CE6CE001B371E /* video-with-audio-and-web-audio.html */, CD577798211CDE8F001B371E /* web-audio-only.html */, 57663DF22357E45D00E85E09 /* web-authentication-get-assertion-hid-cancel.html */, diff --git a/Tools/TestWebKitAPI/Tests/WebKitCocoa/SystemPreview.mm b/Tools/TestWebKitAPI/Tests/WebKitCocoa/SystemPreview.mm index c7b355a5cca0..1eb66a666867 100644 --- a/Tools/TestWebKitAPI/Tests/WebKitCocoa/SystemPreview.mm +++ b/Tools/TestWebKitAPI/Tests/WebKitCocoa/SystemPreview.mm @@ -82,13 +82,73 @@ - (void)userContentController:(WKUserContentController *)userContentController d @end +@interface TestSystemPreviewUIDelegate : NSObject +@property (nonatomic, weak) UIViewController *viewController; +@end + +@implementation TestSystemPreviewUIDelegate +- (UIViewController *)_presentingViewControllerForWebView:(WKWebView *)webView +{ + return _viewController; +} +@end + namespace TestWebKitAPI { +TEST(WebKit, SystemPreviewLoad) +{ + auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES]; + [configuration _setSystemPreviewEnabled:YES]; + + auto viewController = adoptNS([[UIViewController alloc] init]); + auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration]); + auto uiDelegate = adoptNS([[TestSystemPreviewUIDelegate alloc] init]); + uiDelegate.get().viewController = viewController.get(); + [webView setUIDelegate:uiDelegate.get()]; + [viewController setView:webView.get()]; + + [webView synchronouslyLoadTestPageNamed:@"system-preview"]; + + [webView _setSystemPreviewCompletionHandlerForLoadTesting:^(bool success) { + EXPECT_TRUE(success); + wasTriggered = true; + }]; + + [webView evaluateJavaScript:@"arlink.click()" completionHandler:nil]; + + Util::run(&wasTriggered); +} + +TEST(WebKit, SystemPreviewFail) +{ + auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES]; + [configuration _setSystemPreviewEnabled:YES]; + + auto viewController = adoptNS([[UIViewController alloc] init]); + auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration]); + auto uiDelegate = adoptNS([[TestSystemPreviewUIDelegate alloc] init]); + uiDelegate.get().viewController = viewController.get(); + [webView setUIDelegate:uiDelegate.get()]; + [viewController setView:webView.get()]; + + [webView synchronouslyLoadTestPageNamed:@"system-preview"]; + + [webView _setSystemPreviewCompletionHandlerForLoadTesting:^(bool success) { + EXPECT_FALSE(success); + wasTriggered = true; + }]; + + [webView evaluateJavaScript:@"badlink.click()" completionHandler:nil]; + + Util::run(&wasTriggered); +} + TEST(WebKit, SystemPreviewTriggered) { auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES]; auto messageHandler = adoptNS([[TestSystemPreviewTriggeredHandler alloc] init]); [[configuration userContentController] addScriptMessageHandler:messageHandler.get() name:@"testSystemPreview"]; + [configuration _setSystemPreviewEnabled:YES]; auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration]); [webView synchronouslyLoadTestPageNamed:@"system-preview-trigger"]; @@ -103,6 +163,7 @@ - (void)userContentController:(WKUserContentController *)userContentController d auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"WebProcessPlugInWithInternals" configureJSCForTesting:YES]; auto messageHandler = adoptNS([[TestSystemPreviewTriggeredOnDetachedElementHandler alloc] init]); [[configuration userContentController] addScriptMessageHandler:messageHandler.get() name:@"testSystemPreview"]; + [configuration _setSystemPreviewEnabled:YES]; auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero configuration:configuration]); [webView synchronouslyLoadTestPageNamed:@"system-preview-trigger"]; diff --git a/Tools/TestWebKitAPI/Tests/WebKitCocoa/UnitBox.usdz b/Tools/TestWebKitAPI/Tests/WebKitCocoa/UnitBox.usdz new file mode 100644 index 000000000000..16b711829e01 Binary files /dev/null and b/Tools/TestWebKitAPI/Tests/WebKitCocoa/UnitBox.usdz differ diff --git a/Tools/TestWebKitAPI/Tests/WebKitCocoa/system-preview-trigger.html b/Tools/TestWebKitAPI/Tests/WebKitCocoa/system-preview-trigger.html index c11f222b6b32..064e27529292 100644 --- a/Tools/TestWebKitAPI/Tests/WebKitCocoa/system-preview-trigger.html +++ b/Tools/TestWebKitAPI/Tests/WebKitCocoa/system-preview-trigger.html @@ -22,8 +22,4 @@ const detachedElement = document.createElement("a"); runTest(detachedElement, "triggered_detached", "loaded_triggered_detached"); }); - - - - diff --git a/Tools/TestWebKitAPI/Tests/WebKitCocoa/system-preview.html b/Tools/TestWebKitAPI/Tests/WebKitCocoa/system-preview.html new file mode 100644 index 000000000000..97e5ee6002f0 --- /dev/null +++ b/Tools/TestWebKitAPI/Tests/WebKitCocoa/system-preview.html @@ -0,0 +1,8 @@ + + + + + + + +