Diff
Modified: trunk/Source/WebCore/ChangeLog (243112 => 243113)
--- trunk/Source/WebCore/ChangeLog 2019-03-18 22:45:47 UTC (rev 243112)
+++ trunk/Source/WebCore/ChangeLog 2019-03-18 23:32:20 UTC (rev 243113)
@@ -1,3 +1,13 @@
+2019-03-18 Timothy Hatcher <timo...@apple.com>
+
+ Add new NSAttributedString API for converting HTML.
+ https://bugs.webkit.org/show_bug.cgi?id=195636
+ rdar://problem/45055697
+
+ Reviewed by Tim Horton.
+
+ * en.lproj/Localizable.strings: Updated.
+
2019-03-18 Zalan Bujtas <za...@apple.com>
Call transition and animation callbacks on non-composited renderers too.
Modified: trunk/Source/WebCore/en.lproj/Localizable.strings (243112 => 243113)
--- trunk/Source/WebCore/en.lproj/Localizable.strings 2019-03-18 22:45:47 UTC (rev 243112)
+++ trunk/Source/WebCore/en.lproj/Localizable.strings 2019-03-18 23:32:20 UTC (rev 243113)
@@ -109,6 +109,9 @@
/* Malware confirmation dialog title */
"Are you sure you wish to go to this site?" = "Are you sure you wish to go to this site?";
+/* WKErrorAttributedStringContentFailedToLoad description */
+"Attributed string content failed to load" = "Attributed string content failed to load";
+
/* Menu item label for automatic track selection behavior */
"Auto (Recommended)" = "Auto (Recommended)";
@@ -802,6 +805,9 @@
/* Undo action name */
"Tighten Kerning (Undo action name)" = "Tighten Kerning";
+/* WKErrorAttributedStringContentLoadTimedOut description */
+"Timed out while loading attributed string content" = "Timed out while loading attributed string content";
+
/* prompt string in authentication panel */
"To view this page, you must log in to area “%@” on %@." = "To view this page, you must log in to area “%@” on %@.";
Modified: trunk/Source/WebKit/ChangeLog (243112 => 243113)
--- trunk/Source/WebKit/ChangeLog 2019-03-18 22:45:47 UTC (rev 243112)
+++ trunk/Source/WebKit/ChangeLog 2019-03-18 23:32:20 UTC (rev 243113)
@@ -1,3 +1,42 @@
+2019-03-18 Timothy Hatcher <timo...@apple.com>
+
+ Add new NSAttributedString API for converting HTML.
+ https://bugs.webkit.org/show_bug.cgi?id=195636
+ rdar://problem/45055697
+
+ Reviewed by Tim Horton.
+
+ * Platform/spi/ios/UIKitSPI.h:
+ * SourcesCocoa.txt:
+ * UIProcess/API/Cocoa/NSAttributedString.h: Added.
+ * UIProcess/API/Cocoa/NSAttributedString.mm: Added.
+ (-[_WKAttributedStringNavigationDelegate webView:decidePolicyForNavigationAction:decisionHandler:]):
+ (-[_WKAttributedStringNavigationDelegate webView:didFailProvisionalNavigation:withError:]):
+ (-[_WKAttributedStringNavigationDelegate webView:didFailNavigation:withError:]):
+ (-[_WKAttributedStringNavigationDelegate webView:didFinishNavigation:]):
+ (+[_WKAttributedStringWebViewCache cache]):
+ (+[_WKAttributedStringWebViewCache configuration]):
+ (+[_WKAttributedStringWebViewCache clearConfiguration]):
+ (+[_WKAttributedStringWebViewCache retrieveOrCreateWebView]):
+ (+[_WKAttributedStringWebViewCache cacheWebView:]):
+ (+[_WKAttributedStringWebViewCache resetPurgeDelay]):
+ (+[_WKAttributedStringWebViewCache purgeSingleWebView]):
+ (+[_WKAttributedStringWebViewCache purgeAllWebViews]):
+ (+[NSAttributedString _loadFromHTMLWithOptions:contentLoader:completionHandler:]):
+ (+[NSAttributedString loadFromHTMLWithRequest:options:completionHandler:]):
+ (+[NSAttributedString loadFromHTMLWithFileURL:options:completionHandler:]):
+ (+[NSAttributedString loadFromHTMLWithString:options:completionHandler:]):
+ (+[NSAttributedString loadFromHTMLWithData:options:completionHandler:]):
+ * UIProcess/API/Cocoa/NSAttributedStringPrivate.h: Copied from Source/WebKit/UIProcess/API/Cocoa/WKErrorInternal.h.
+ * UIProcess/API/Cocoa/WKError.h:
+ * UIProcess/API/Cocoa/WKError.mm:
+ (localizedDescriptionForErrorCode):
+ (createNSError):
+ * UIProcess/API/Cocoa/WKErrorInternal.h:
+ * WebKit.xcodeproj/project.pbxproj:
+ * WebProcess/WebPage/Cocoa/WebPageCocoa.mm:
+ (WebKit::WebPage::getContentsAsAttributedString):
+
2019-03-18 Alex Christensen <achristen...@webkit.org>
Implement DownloadMonitor to prevent long-running slow downloads from background apps
Modified: trunk/Source/WebKit/Platform/spi/ios/UIKitSPI.h (243112 => 243113)
--- trunk/Source/WebKit/Platform/spi/ios/UIKitSPI.h 2019-03-18 22:45:47 UTC (rev 243112)
+++ trunk/Source/WebKit/Platform/spi/ios/UIKitSPI.h 2019-03-18 23:32:20 UTC (rev 243113)
@@ -1193,4 +1193,11 @@
extern NSString *const UIBacklightLevelChangedNotification;
+extern NSString * const NSTextEncodingNameDocumentOption;
+extern NSString * const NSBaseURLDocumentOption;
+extern NSString * const NSTimeoutDocumentOption;
+extern NSString * const NSWebPreferencesDocumentOption;
+extern NSString * const NSWebResourceLoadDelegateDocumentOption;
+extern NSString * const NSTextSizeMultiplierDocumentOption;
+
WTF_EXTERN_C_END
Modified: trunk/Source/WebKit/SourcesCocoa.txt (243112 => 243113)
--- trunk/Source/WebKit/SourcesCocoa.txt 2019-03-18 22:45:47 UTC (rev 243112)
+++ trunk/Source/WebKit/SourcesCocoa.txt 2019-03-18 23:32:20 UTC (rev 243113)
@@ -272,6 +272,7 @@
UIProcess/API/Cocoa/APISerializedScriptValueCocoa.mm
UIProcess/API/Cocoa/APIWebsiteDataStoreCocoa.mm
UIProcess/API/Cocoa/LegacyBundleForClass.mm
+UIProcess/API/Cocoa/NSAttributedString.mm
UIProcess/API/Cocoa/WKBackForwardList.mm
UIProcess/API/Cocoa/WKBackForwardListItem.mm
UIProcess/API/Cocoa/WKBrowsingContextController.mm
Added: trunk/Source/WebKit/UIProcess/API/Cocoa/NSAttributedString.h (0 => 243113)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/NSAttributedString.h (rev 0)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/NSAttributedString.h 2019-03-18 23:32:20 UTC (rev 243113)
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#import <WebKit/WKFoundation.h>
+
+#if TARGET_OS_IPHONE
+#import <UIKit/NSAttributedString.h>
+#else
+#import <AppKit/NSAttributedString.h>
+#endif
+
+NS_ASSUME_NONNULL_BEGIN
+
+/*!
+ @abstract Indicates which local files WebKit can access when loading content.
+ @discussion If NSReadAccessURLDocumentOption references a single file, only that file may be
+ loaded by WebKit. If NSReadAccessURLDocumentOption references a directory, files inside that
+ directory may be loaded by WebKit.
+*/
+WK_EXTERN NSAttributedStringDocumentReadingOptionKey const NSReadAccessURLDocumentOption
+ NS_SWIFT_NAME(NSAttributedStringDocumentReadingOptionKey.readAccessURL) WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
+
+/*!
+ @abstract Type definition for the completion handler block used to get asynchronous attributed strings.
+ @discussion The completion handler block is passed the attributed string result along with any
+ document-level attributes, like NSBackgroundColorDocumentAttribute, or an error. An implementation
+ of this block type must expect to be called asynchronously when passed to HTML loading methods.
+*/
+typedef void (^NSAttributedStringCompletionHandler)(NSAttributedString * _Nullable, NSDictionary<NSAttributedStringDocumentAttributeKey, id> * _Nullable, NSError * _Nullable)
+ NS_SWIFT_NAME(NSAttributedString.CompletionHandler) WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
+
+/*!
+ @discussion Extension of @link //apple_ref/occ/NSAttributedString NSAttributedString @/link to
+ create attributed strings from HTML content using WebKit.
+*/
+@interface NSAttributedString (NSAttributedStringWebKitAdditions)
+
+/*!
+ @abstract Loads an HTML URL request and converts the contents into an attributed string.
+ @param request The request specifying the URL to load.
+ @param options Document attributes for interpreting the document contents.
+ NSTextSizeMultiplierDocumentOption and NSTimeoutDocumentOption are supported option keys.
+ @param completionHandler A block to invoke when the operation completes or fails.
+ @discussion The completionHandler is passed the attributed string result along with any
+ document-level attributes, or an error.
+*/
++ (void)loadFromHTMLWithRequest:(NSURLRequest *)request options:(NSDictionary<NSAttributedStringDocumentReadingOptionKey, id> *)options completionHandler:(NSAttributedStringCompletionHandler)completionHandler
+ NS_SWIFT_NAME(loadFromHTML(request:options:completionHandler:)) WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
+
+/*!
+ @abstract Converts a local HTML file into an attributed string.
+ @param fileURL The file URL to load.
+ @param options Document attributes for interpreting the document contents.
+ NSTextSizeMultiplierDocumentOption, NSTimeoutDocumentOption and NSReadAccessURLDocumentOption
+ are supported option keys.
+ @param completionHandler A block to invoke when the operation completes or fails.
+ @discussion The completionHandler is passed the attributed string result along with any
+ document-level attributes, or an error. If NSReadAccessURLDocumentOption references a single file,
+ only that file may be loaded by WebKit. If NSReadAccessURLDocumentOption references a directory,
+ files inside that directory may be loaded by WebKit.
+*/
++ (void)loadFromHTMLWithFileURL:(NSURL *)fileURL options:(NSDictionary<NSAttributedStringDocumentReadingOptionKey, id> *)options completionHandler:(NSAttributedStringCompletionHandler)completionHandler
+ NS_SWIFT_NAME(loadFromHTML(fileURL:options:completionHandler:)) WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
+
+/*!
+ @abstract Converts an HTML string into an attributed string.
+ @param string The HTML string to use as the contents.
+ @param options Document attributes for interpreting the document contents.
+ NSTextSizeMultiplierDocumentOption, NSTimeoutDocumentOption and NSBaseURLDocumentOption
+ are supported option keys.
+ @param completionHandler A block to invoke when the operation completes or fails.
+ @discussion The completionHandler is passed the attributed string result along with any
+ document-level attributes, or an error. NSBaseURLDocumentOption is used to resolve relative URLs
+ within the document.
+*/
++ (void)loadFromHTMLWithString:(NSString *)string options:(NSDictionary<NSAttributedStringDocumentReadingOptionKey, id> *)options completionHandler:(NSAttributedStringCompletionHandler)completionHandler
+ NS_SWIFT_NAME(loadFromHTML(string:options:completionHandler:)) WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
+
+/*!
+ @abstract Converts HTML data into an attributed string.
+ @param data The HTML data to use as the contents.
+ @param options Document attributes for interpreting the document contents.
+ NSTextSizeMultiplierDocumentOption, NSTimeoutDocumentOption, NSTextEncodingNameDocumentOption,
+ and NSCharacterEncodingDocumentOption are supported option keys.
+ @param completionHandler A block to invoke when the operation completes or fails.
+ @discussion The completionHandler is passed the attributed string result along with any
+ document-level attributes, or an error. If neither NSTextEncodingNameDocumentOption nor
+ NSCharacterEncodingDocumentOption is supplied, a best-guess encoding is used.
+*/
++ (void)loadFromHTMLWithData:(NSData *)data options:(NSDictionary<NSAttributedStringDocumentReadingOptionKey, id> *)options completionHandler:(NSAttributedStringCompletionHandler)completionHandler
+ NS_SWIFT_NAME(loadFromHTML(data:options:completionHandler:)) WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
+
+@end
+
+NS_ASSUME_NONNULL_END
Added: trunk/Source/WebKit/UIProcess/API/Cocoa/NSAttributedString.mm (0 => 243113)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/NSAttributedString.mm (rev 0)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/NSAttributedString.mm 2019-03-18 23:32:20 UTC (rev 243113)
@@ -0,0 +1,372 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#import "config.h"
+
+#import "NSAttributedStringPrivate.h"
+
+#import "WKErrorInternal.h"
+#import "WKNavigationActionPrivate.h"
+#import "WKNavigationDelegate.h"
+#import "WKPreferences.h"
+#import "WKProcessPoolPrivate.h"
+#import "WKWebViewConfigurationPrivate.h"
+#import "WKWebViewPrivate.h"
+#import "WKWebsiteDataStore.h"
+#import "_WKProcessPoolConfiguration.h"
+#import <wtf/Deque.h>
+#import <wtf/MemoryPressureHandler.h>
+#import <wtf/RetainPtr.h>
+
+#if PLATFORM(IOS_FAMILY)
+#import <UIKitSPI.h>
+#endif
+
+NSString * const NSReadAccessURLDocumentOption = @"ReadAccessURL";
+
+constexpr NSRect webViewRect = {{0, 0}, {800, 600}};
+constexpr NSTimeInterval defaultTimeoutInterval = 60;
+constexpr NSTimeInterval purgeWebViewCacheDelay = 15;
+constexpr NSUInteger maximumWebViewCacheSize = 3;
+
+@interface _WKAttributedStringNavigationDelegate : NSObject <WKNavigationDelegate>
+
+@property (nonatomic, copy) void (^webContentProcessDidTerminate)(WKWebView *);
+@property (nonatomic, copy) void (^decidePolicyForNavigationAction)(WKNavigationAction *, void (^)(WKNavigationActionPolicy));
+@property (nonatomic, copy) void (^didFailProvisionalNavigation)(WKWebView *, WKNavigation *, NSError *);
+@property (nonatomic, copy) void (^didFailNavigation)(WKWebView *, WKNavigation *, NSError *);
+@property (nonatomic, copy) void (^didFinishNavigation)(WKWebView *, WKNavigation *);
+
+@end
+
+@implementation _WKAttributedStringNavigationDelegate
+
+- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView
+{
+ if (_webContentProcessDidTerminate)
+ _webContentProcessDidTerminate(webView);
+}
+
+- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
+{
+ if (_decidePolicyForNavigationAction)
+ return _decidePolicyForNavigationAction(navigationAction, decisionHandler);
+ decisionHandler(WKNavigationActionPolicyAllow);
+}
+
+- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error
+{
+ if (_didFailProvisionalNavigation)
+ _didFailProvisionalNavigation(webView, navigation, error);
+}
+
+- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error
+{
+ if (_didFailNavigation)
+ _didFailNavigation(webView, navigation, error);
+}
+
+- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
+{
+ if (_didFinishNavigation)
+ _didFinishNavigation(webView, navigation);
+}
+
+@end
+
+@interface _WKAttributedStringWebViewCache : NSObject
+
++ (RetainPtr<WKWebView>)retrieveOrCreateWebView;
++ (void)cacheWebView:(WKWebView *)webView;
+
+@end
+
+@implementation _WKAttributedStringWebViewCache
+
++ (NSMutableArray<WKWebView *> *)cache
+{
+ static auto* cache = [[NSMutableArray alloc] initWithCapacity:maximumWebViewCacheSize];
+ return cache;
+}
+
+static WKWebViewConfiguration *configuration;
+
++ (WKWebViewConfiguration *)configuration
+{
+ if (!configuration) {
+ configuration = [[WKWebViewConfiguration alloc] init];
+ configuration.processPool = [[[WKProcessPool alloc] init] autorelease];
+ configuration.websiteDataStore = [WKWebsiteDataStore nonPersistentDataStore];
+ configuration.mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeAll;
+ configuration._allowsJavaScriptMarkup = NO;
+ configuration._allowsMetaRefresh = NO;
+ configuration._attachmentElementEnabled = YES;
+ configuration._invisibleAutoplayNotPermitted = YES;
+ configuration._mediaDataLoadsAutomatically = NO;
+ configuration._needsStorageAccessFromFileURLsQuirk = NO;
+#if PLATFORM(IOS_FAMILY)
+ configuration.allowsInlineMediaPlayback = NO;
+ configuration._alwaysRunsAtForegroundPriority = YES;
+#endif
+ }
+
+ return configuration;
+}
+
++ (void)clearConfiguration
+{
+ [configuration release];
+ configuration = nil;
+}
+
++ (RetainPtr<WKWebView>)retrieveOrCreateWebView
+{
+ [self resetPurgeDelay];
+
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ auto& memoryPressureHandler = MemoryPressureHandler::singleton();
+ memoryPressureHandler.setLowMemoryHandler([self] (Critical, Synchronous) {
+ [self purgeAllWebViews];
+ });
+ });
+
+ auto* cache = self.cache;
+ if (cache.count) {
+ RetainPtr<WKWebView> webView = cache.lastObject;
+ [cache removeLastObject];
+ return webView;
+ }
+
+ return adoptNS([[WKWebView alloc] initWithFrame:webViewRect configuration:self.configuration]);
+}
+
++ (void)cacheWebView:(WKWebView *)webView
+{
+ auto* cache = self.cache;
+ if (cache.count >= maximumWebViewCacheSize)
+ return;
+
+ [cache addObject:webView];
+
+ // Load a blank page to clear anything loaded while in the cache.
+ [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"about:blank"]]];
+}
+
++ (void)resetPurgeDelay
+{
+ static const auto purgeSelector = @selector(purgeSingleWebView);
+ [NSObject cancelPreviousPerformRequestsWithTarget:self selector:purgeSelector object:nil];
+ [self performSelector:purgeSelector withObject:nil afterDelay:purgeWebViewCacheDelay];
+}
+
++ (void)purgeSingleWebView
+{
+ [NSObject cancelPreviousPerformRequestsWithTarget:self selector:_cmd object:nil];
+
+ auto* cache = self.cache;
+ if (!cache.count)
+ return;
+
+ [cache.lastObject _close];
+ [cache removeLastObject];
+
+ if (!cache.count) {
+ [self clearConfiguration];
+ return;
+ }
+
+ // Keep going until every view is removed, or the delay is reset.
+ [self performSelector:_cmd withObject:nil afterDelay:purgeWebViewCacheDelay];
+}
+
++ (void)purgeAllWebViews
+{
+ auto* cache = self.cache;
+ if (!cache.count)
+ return;
+
+ [cache makeObjectsPerformSelector:@selector(_close)];
+ [cache removeAllObjects];
+
+ [self clearConfiguration];
+}
+
+@end
+
+@implementation NSAttributedString (WKPrivate)
+
++ (void)_loadFromHTMLWithOptions:(NSDictionary<NSAttributedStringDocumentReadingOptionKey, id> *)options contentLoader:(WKNavigation *(^)(WKWebView *))loadWebContent completionHandler:(NSAttributedStringCompletionHandler)completionHandler
+{
+ if (options[NSWebPreferencesDocumentOption])
+ [NSException raise:NSInvalidArgumentException format:@"NSWebPreferencesDocumentOption option is not supported"];
+ if (options[NSWebResourceLoadDelegateDocumentOption])
+ [NSException raise:NSInvalidArgumentException format:@"NSWebResourceLoadDelegateDocumentOption option is not supported"];
+ if (options[@"WebPolicyDelegate"])
+ [NSException raise:NSInvalidArgumentException format:@"WebPolicyDelegate option is not supported"];
+
+ auto runConversion = ^{
+ __block auto finished = NO;
+ __block auto webView = [_WKAttributedStringWebViewCache retrieveOrCreateWebView];
+ __block auto navigationDelegate = adoptNS([[_WKAttributedStringNavigationDelegate alloc] init]);
+
+ __block RetainPtr<WKNavigation> contentNavigation;
+
+ webView.get().navigationDelegate = navigationDelegate.get();
+
+ if (auto* textZoomFactor = dynamic_objc_cast<NSNumber>(options[NSTextSizeMultiplierDocumentOption]))
+ webView.get()._textZoomFactor = textZoomFactor.doubleValue;
+ else
+ webView.get()._textZoomFactor = 1;
+
+ auto finish = ^(NSAttributedString *attributedString, NSDictionary<NSAttributedStringDocumentAttributeKey, id> *attributes, NSError *error) {
+ if (finished)
+ return;
+
+ finished = YES;
+
+ webView.get().navigationDelegate = nil;
+ navigationDelegate = nil;
+ contentNavigation = nil;
+
+ if (!error)
+ [_WKAttributedStringWebViewCache cacheWebView:webView.get()];
+ webView = nil;
+
+ // Make the string be an instance of the receiver class.
+ if (attributedString && self != attributedString.class)
+ attributedString = [[[self alloc] initWithAttributedString:attributedString] autorelease];
+
+ // Make the document attributes immutable.
+ if ([attributes isKindOfClass:NSMutableDictionary.class])
+ attributes = [[[NSDictionary alloc] initWithDictionary:attributes] autorelease];
+
+ completionHandler(attributedString, attributes, error);
+ };
+
+ auto cancel = ^(WKErrorCode errorCode, NSError* underlyingError) {
+ finish(nil, nil, createNSError(errorCode, underlyingError).get());
+ };
+
+ navigationDelegate.get().decidePolicyForNavigationAction = ^(WKNavigationAction *action, void (^decisionHandler)(WKNavigationActionPolicy)) {
+ if ([action._mainFrameNavigation isEqual:contentNavigation.get()])
+ return decisionHandler(WKNavigationActionPolicyAllow);
+ decisionHandler(WKNavigationActionPolicyCancel);
+ };
+
+ navigationDelegate.get().webContentProcessDidTerminate = ^(WKWebView *) {
+ cancel(WKErrorWebContentProcessTerminated, nil);
+ };
+
+ navigationDelegate.get().didFailProvisionalNavigation = ^(WKWebView *, WKNavigation *, NSError *error) {
+ cancel(WKErrorAttributedStringContentFailedToLoad, error);
+ };
+
+ navigationDelegate.get().didFailNavigation = ^(WKWebView *, WKNavigation *, NSError *error) {
+ cancel(WKErrorAttributedStringContentFailedToLoad, error);
+ };
+
+ navigationDelegate.get().didFinishNavigation = ^(WKWebView *, WKNavigation *) {
+ if (finished)
+ return;
+
+ navigationDelegate = nil;
+
+ [webView _getContentsAsAttributedStringWithCompletionHandler:^(NSAttributedString *attributedString, NSDictionary<NSAttributedStringDocumentAttributeKey, id> *documentAttributes, NSError *error) {
+ if (error)
+ return cancel(WKErrorUnknown, error);
+ finish([[attributedString retain] autorelease], [[documentAttributes retain] autorelease], nil);
+ }];
+ };
+
+ auto timeoutInterval = defaultTimeoutInterval;
+ if (auto* timeoutOption = dynamic_objc_cast<NSNumber>(options[NSTimeoutDocumentOption])) {
+ if (timeoutOption.doubleValue >= 0)
+ timeoutInterval = timeoutOption.doubleValue;
+ }
+
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, timeoutInterval * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
+ if (finished)
+ return;
+ cancel(WKErrorAttributedStringContentLoadTimedOut, nil);
+ });
+
+ contentNavigation = loadWebContent(webView.get());
+
+ ASSERT(contentNavigation);
+ ASSERT(webView.get().loading);
+ };
+
+ if ([NSThread isMainThread])
+ runConversion();
+ else
+ dispatch_async(dispatch_get_main_queue(), runConversion);
+}
+
+@end
+
+@implementation NSAttributedString (NSAttributedStringWebKitAdditions)
+
++ (void)loadFromHTMLWithRequest:(NSURLRequest *)request options:(NSDictionary<NSAttributedStringDocumentReadingOptionKey, id> *)options completionHandler:(NSAttributedStringCompletionHandler)completionHandler
+{
+ [self _loadFromHTMLWithOptions:options contentLoader:^WKNavigation *(WKWebView *webView) {
+ return [webView loadRequest:request];
+ } completionHandler:completionHandler];
+}
+
++ (void)loadFromHTMLWithFileURL:(NSURL *)fileURL options:(NSDictionary<NSAttributedStringDocumentReadingOptionKey, id> *)options completionHandler:(NSAttributedStringCompletionHandler)completionHandler
+{
+ [self _loadFromHTMLWithOptions:options contentLoader:^WKNavigation *(WKWebView *webView) {
+ auto* readAccessURL = dynamic_objc_cast<NSURL>(options[NSReadAccessURLDocumentOption]);
+ return [webView loadFileURL:fileURL allowingReadAccessToURL:readAccessURL];
+ } completionHandler:completionHandler];
+}
+
++ (void)loadFromHTMLWithString:(NSString *)string options:(NSDictionary<NSAttributedStringDocumentReadingOptionKey, id> *)options completionHandler:(NSAttributedStringCompletionHandler)completionHandler
+{
+ [self _loadFromHTMLWithOptions:options contentLoader:^WKNavigation *(WKWebView *webView) {
+ auto* baseURL = dynamic_objc_cast<NSURL>(options[NSBaseURLDocumentOption]);
+ return [webView loadHTMLString:string baseURL:baseURL];
+ } completionHandler:completionHandler];
+}
+
++ (void)loadFromHTMLWithData:(NSData *)data options:(NSDictionary<NSAttributedStringDocumentReadingOptionKey, id> *)options completionHandler:(NSAttributedStringCompletionHandler)completionHandler
+{
+ [self _loadFromHTMLWithOptions:options contentLoader:^WKNavigation *(WKWebView *webView) {
+ auto* textEncodingName = dynamic_objc_cast<NSString>(options[NSTextEncodingNameDocumentOption]);
+ auto characterEncoding = static_cast<NSStringEncoding>(dynamic_objc_cast<NSNumber>(options[NSCharacterEncodingDocumentOption]).unsignedIntegerValue);
+ auto* baseURL = dynamic_objc_cast<NSURL>(options[NSBaseURLDocumentOption]);
+
+ if (characterEncoding && !textEncodingName) {
+ auto stringEncoding = CFStringConvertNSStringEncodingToEncoding(characterEncoding);
+ if (stringEncoding != kCFStringEncodingInvalidId)
+ textEncodingName = (__bridge NSString *)CFStringConvertEncodingToIANACharSetName(stringEncoding);
+ }
+
+ return [webView loadData:data MIMEType:@"text/html" characterEncodingName:textEncodingName baseURL:baseURL];
+ } completionHandler:completionHandler];
+}
+
+@end
Copied: trunk/Source/WebKit/UIProcess/API/Cocoa/NSAttributedStringPrivate.h (from rev 243112, trunk/Source/WebKit/UIProcess/API/Cocoa/WKErrorInternal.h) (0 => 243113)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/NSAttributedStringPrivate.h (rev 0)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/NSAttributedStringPrivate.h 2019-03-18 23:32:20 UTC (rev 243113)
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#import <WebKit/NSAttributedString.h>
+
+@class WKNavigation;
+@class WKWebView;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/*!
+ @discussion Private extension of @link //apple_ref/occ/NSAttributedString NSAttributedString @/link to
+ translate HTML content into attributed strings using WebKit.
+ */
+@interface NSAttributedString (WKPrivate)
+
+/*!
+ @abstract Converts the contents loaded by a content loader block into an attributed string.
+ @param options Document attributes for interpreting the document contents.
+ NSTextSizeMultiplierDocumentOption, and NSTimeoutDocumentOption are supported option keys.
+ @param contentLoader A block to invoke when content needs to be loaded in the supplied
+ @link WKWebView @/link. A @link WKNavigation @/link for the main frame must be returned.
+ @param completionHandler A block to invoke when the translation completes or fails.
+ @discussion The completionHandler is passed the attributed string result along with any
+ document-level attributes, or an error.
+ */
++ (void)_loadFromHTMLWithOptions:(NSDictionary<NSAttributedStringDocumentReadingOptionKey, id> *)options contentLoader:(WKNavigation *(^)(WKWebView *))loadWebContent completionHandler:(NSAttributedStringCompletionHandler)completionHandler;
+
+@end
+
+NS_ASSUME_NONNULL_END
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKError.h (243112 => 243113)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKError.h 2019-03-18 22:45:47 UTC (rev 243112)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKError.h 2019-03-18 23:32:20 UTC (rev 243113)
@@ -43,6 +43,8 @@
@constant WKErrorContentRuleListStoreLookUpFailed Indicates that looking up a WKUserContentRuleList failed.
@constant WKErrorContentRuleListStoreRemoveFailed Indicates that removing a WKUserContentRuleList failed.
@constant WKErrorContentRuleListStoreVersionMismatch Indicates that the WKUserContentRuleList version did not match the latest.
+ @constant WKErrorAttributedStringContentFailedToLoad Indicates that the attributed string content failed to load.
+ @constant WKErrorAttributedStringContentLoadTimedOut Indicates that loading attributed string content timed out.
*/
typedef NS_ENUM(NSInteger, WKErrorCode) {
WKErrorUnknown = 1,
@@ -54,6 +56,8 @@
WKErrorContentRuleListStoreLookUpFailed WK_API_AVAILABLE(macosx(10.13), ios(11.0)),
WKErrorContentRuleListStoreRemoveFailed WK_API_AVAILABLE(macosx(10.13), ios(11.0)),
WKErrorContentRuleListStoreVersionMismatch WK_API_AVAILABLE(macosx(10.13), ios(11.0)),
+ WKErrorAttributedStringContentFailedToLoad WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA)),
+ WKErrorAttributedStringContentLoadTimedOut WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA)),
} WK_API_AVAILABLE(macosx(10.10), ios(8.0));
NS_ASSUME_NONNULL_END
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKError.mm (243112 => 243113)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKError.mm 2019-03-18 22:45:47 UTC (rev 243112)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKError.mm 2019-03-18 23:32:20 UTC (rev 243113)
@@ -67,12 +67,22 @@
case WKErrorContentRuleListStoreRemoveFailed:
return WEB_UI_STRING("Removing a WKContentRuleList failed", "WKErrorContentRuleListStoreRemoveFailed description");
+
+ case WKErrorAttributedStringContentFailedToLoad:
+ return WEB_UI_STRING("Attributed string content failed to load", "WKErrorAttributedStringContentFailedToLoad description");
+
+ case WKErrorAttributedStringContentLoadTimedOut:
+ return WEB_UI_STRING("Timed out while loading attributed string content", "WKErrorAttributedStringContentLoadTimedOut description");
}
}
-RetainPtr<NSError> createNSError(WKErrorCode errorCode)
+RetainPtr<NSError> createNSError(WKErrorCode errorCode, NSError* underlyingError)
{
- auto userInfo = adoptNS([[NSDictionary alloc] initWithObjectsAndKeys:localizedDescriptionForErrorCode(errorCode), NSLocalizedDescriptionKey, nil]);
+ NSDictionary *userInfo = nil;
+ if (underlyingError)
+ userInfo = @{ NSLocalizedDescriptionKey: localizedDescriptionForErrorCode(errorCode), NSUnderlyingErrorKey: underlyingError };
+ else
+ userInfo = @{ NSLocalizedDescriptionKey: localizedDescriptionForErrorCode(errorCode) };
- return adoptNS([[NSError alloc] initWithDomain:WKErrorDomain code:errorCode userInfo:userInfo.get()]);
+ return adoptNS([[NSError alloc] initWithDomain:WKErrorDomain code:errorCode userInfo:userInfo]);
}
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKErrorInternal.h (243112 => 243113)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKErrorInternal.h 2019-03-18 22:45:47 UTC (rev 243112)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKErrorInternal.h 2019-03-18 23:32:20 UTC (rev 243113)
@@ -28,5 +28,5 @@
#import <wtf/RetainPtr.h>
#import "GenericCallback.h"
-RetainPtr<NSError> createNSError(WKErrorCode);
+RetainPtr<NSError> createNSError(WKErrorCode, NSError* underlyingError = nil);
NSString *localizedDescriptionForErrorCode(WKErrorCode);
Modified: trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj (243112 => 243113)
--- trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj 2019-03-18 22:45:47 UTC (rev 243112)
+++ trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj 2019-03-18 23:32:20 UTC (rev 243113)
@@ -385,6 +385,8 @@
1C0A19571C90068F00FE0EBB /* WebAutomationSessionMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1C0A19551C90068F00FE0EBB /* WebAutomationSessionMessageReceiver.cpp */; };
1C0A19581C90068F00FE0EBB /* WebAutomationSessionMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C0A19561C90068F00FE0EBB /* WebAutomationSessionMessages.h */; };
1C0A195C1C916E1B00FE0EBB /* WebAutomationSessionProxyScriptSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C0A195B1C916E1B00FE0EBB /* WebAutomationSessionProxyScriptSource.h */; };
+ 1C20936022318CB000026A39 /* NSAttributedString.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C20935E22318CB000026A39 /* NSAttributedString.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 1C2184022233872800BAC700 /* NSAttributedStringPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C2184012233872800BAC700 /* NSAttributedStringPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; };
1C891D6619B124FF00BA79DD /* WebInspectorUI.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C891D6319B124FF00BA79DD /* WebInspectorUI.h */; };
1C8E28201275D15400BC7BD0 /* WebInspector.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C8E281E1275D15400BC7BD0 /* WebInspector.h */; };
1C8E28341275D73800BC7BD0 /* WebInspectorProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C8E28321275D73800BC7BD0 /* WebInspectorProxy.h */; };
@@ -2396,6 +2398,9 @@
1C0A19591C9006EA00FE0EBB /* WebAutomationSession.messages.in */ = {isa = PBXFileReference; lastKnownFileType = text; path = WebAutomationSession.messages.in; sourceTree = "<group>"; };
1C0A195A1C91669500FE0EBB /* WebAutomationSessionProxy.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode._javascript_; path = WebAutomationSessionProxy.js; sourceTree = "<group>"; };
1C0A195B1C916E1B00FE0EBB /* WebAutomationSessionProxyScriptSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WebAutomationSessionProxyScriptSource.h; path = DerivedSources/WebKit2/WebAutomationSessionProxyScriptSource.h; sourceTree = BUILT_PRODUCTS_DIR; };
+ 1C20935E22318CB000026A39 /* NSAttributedString.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NSAttributedString.h; sourceTree = "<group>"; };
+ 1C20935F22318CB000026A39 /* NSAttributedString.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = NSAttributedString.mm; sourceTree = "<group>"; };
+ 1C2184012233872800BAC700 /* NSAttributedStringPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSAttributedStringPrivate.h; sourceTree = "<group>"; };
1C77C1951288A872006A742F /* WebInspectorProxy.messages.in */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebInspectorProxy.messages.in; sourceTree = "<group>"; };
1C891D6219B124FF00BA79DD /* WebInspectorUI.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebInspectorUI.cpp; sourceTree = "<group>"; };
1C891D6319B124FF00BA79DD /* WebInspectorUI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebInspectorUI.h; sourceTree = "<group>"; };
@@ -6141,6 +6146,9 @@
FED3C1DA1B447AE800E0EB7F /* APISerializedScriptValueCocoa.mm */,
1A3635AB1A3145E500ED6197 /* APIWebsiteDataStoreCocoa.mm */,
1AFDE64319510B5500C48FFA /* LegacyBundleForClass.mm */,
+ 1C20935E22318CB000026A39 /* NSAttributedString.h */,
+ 1C20935F22318CB000026A39 /* NSAttributedString.mm */,
+ 1C2184012233872800BAC700 /* NSAttributedStringPrivate.h */,
37C4C08B1814AC5C003688B9 /* WKBackForwardList.h */,
37C4C08A1814AC5C003688B9 /* WKBackForwardList.mm */,
37C4C08E1814AF3A003688B9 /* WKBackForwardListInternal.h */,
@@ -9293,6 +9301,8 @@
1A2161B011F37664008AD0F5 /* NPRuntimeObjectMap.h in Headers */,
1A2162B111F38971008AD0F5 /* NPRuntimeUtilities.h in Headers */,
1A2D84A3127F6AD1001EB962 /* NPVariantData.h in Headers */,
+ 1C20936022318CB000026A39 /* NSAttributedString.h in Headers */,
+ 1C2184022233872800BAC700 /* NSAttributedStringPrivate.h in Headers */,
3754D5451B3A29FD003A4C7F /* NSInvocationSPI.h in Headers */,
BC8ACA1316670D89004C1941 /* ObjCObjectGraph.h in Headers */,
37B47E2D1D64DB76005F4EFF /* objcSPI.h in Headers */,
Modified: trunk/Source/WebKit/WebProcess/WebPage/Cocoa/WebPageCocoa.mm (243112 => 243113)
--- trunk/Source/WebKit/WebProcess/WebPage/Cocoa/WebPageCocoa.mm 2019-03-18 22:45:47 UTC (rev 243112)
+++ trunk/Source/WebKit/WebProcess/WebPage/Cocoa/WebPageCocoa.mm 2019-03-18 23:32:20 UTC (rev 243113)
@@ -208,6 +208,10 @@
Frame& frame = m_page->mainFrame();
RefPtr<Range> range = TextIterator::rangeFromLocationAndLength(frame.document()->documentElement(), 0, INT_MAX);
+ if (!range) {
+ completionHandler({ });
+ return;
+ }
NSDictionary* documentAttributes = nil;