Diff
Modified: trunk/Source/WebCore/ChangeLog (260864 => 260865)
--- trunk/Source/WebCore/ChangeLog 2020-04-29 04:26:12 UTC (rev 260864)
+++ trunk/Source/WebCore/ChangeLog 2020-04-29 05:16:23 UTC (rev 260865)
@@ -1,3 +1,31 @@
+2020-04-28 Wenson Hsieh <[email protected]>
+
+ [Text manipulation] Add a userInfo dictionary to _WKTextManipulationToken
+ https://bugs.webkit.org/show_bug.cgi?id=211151
+ <rdar://problem/62329534>
+
+ Reviewed by Darin Adler.
+
+ Add an extensible mechanism for the text manipulation controller to send additional
+ metadata for each text manipulation token through to the WebKit client, for debugging
+ purposes.
+
+ Test: TextManipulation.StartTextManipulationExtractsUserInfo
+
+ * editing/TextManipulationController.cpp:
+ (WebCore::tokenInfo):
+ (WebCore::TextManipulationController::observeParagraphs):
+ * editing/TextManipulationController.h:
+
+ Add TextManipulationTokenInfo, and add an optional TextManipulationTokenInfo member to
+ TextManipulationToken. For now, just send over the document URL, element tag name, and
+ the value of the role attribute.
+
+ (WebCore::TextManipulationController::ManipulationTokenInfo::encode const):
+ (WebCore::TextManipulationController::ManipulationTokenInfo::decode):
+ (WebCore::TextManipulationController::ManipulationToken::encode const):
+ (WebCore::TextManipulationController::ManipulationToken::decode):
+
2020-04-28 Simon Fraser <[email protected]>
Update the xcfilelists.
Modified: trunk/Source/WebCore/editing/TextManipulationController.cpp (260864 => 260865)
--- trunk/Source/WebCore/editing/TextManipulationController.cpp 2020-04-29 04:26:12 UTC (rev 260864)
+++ trunk/Source/WebCore/editing/TextManipulationController.cpp 2020-04-29 05:16:23 UTC (rev 260865)
@@ -258,6 +258,21 @@
return true;
}
+static Optional<TextManipulationController::ManipulationTokenInfo> tokenInfo(Node* node)
+{
+ if (!node)
+ return WTF::nullopt;
+
+ TextManipulationController::ManipulationTokenInfo result;
+ result.documentURL = node->document().url();
+ if (auto element = is<Element>(node) ? makeRefPtr(downcast<Element>(*node)) : makeRefPtr(node->parentElement())) {
+ result.tagName = element->tagName();
+ if (element->hasAttributeWithoutSynchronization(HTMLNames::roleAttr))
+ result.roleAttribute = element->attributeWithoutSynchronization(HTMLNames::roleAttr);
+ }
+ return result;
+}
+
void TextManipulationController::observeParagraphs(const Position& start, const Position& end)
{
if (start.isNull() || end.isNull())
@@ -321,13 +336,13 @@
auto& currentElement = downcast<Element>(*content.node);
if (!content.isTextContent && canPerformTextManipulationByReplacingEntireTextContent(currentElement)) {
addItem(ManipulationItemData { Position(), Position(), makeWeakPtr(currentElement), nullQName(),
- { ManipulationToken { m_tokenIdentifier.generate(), currentElement.textContent() } } });
+ { ManipulationToken { m_tokenIdentifier.generate(), currentElement.textContent(), tokenInfo(¤tElement) } } });
}
if (currentElement.hasAttributes()) {
for (auto& attribute : currentElement.attributesIterator()) {
if (isAttributeForTextManipulation(attribute.name())) {
addItem(ManipulationItemData { Position(), Position(), makeWeakPtr(currentElement), attribute.name(),
- { ManipulationToken { m_tokenIdentifier.generate(), attribute.value() } } });
+ { ManipulationToken { m_tokenIdentifier.generate(), attribute.value(), tokenInfo(¤tElement) } } });
}
}
}
@@ -346,7 +361,7 @@
continue;
endOfCurrentParagraph = currentEndOfCurrentParagraph;
- tokensInCurrentParagraph.append(ManipulationToken { m_tokenIdentifier.generate(), "[]", true });
+ tokensInCurrentParagraph.append(ManipulationToken { m_tokenIdentifier.generate(), "[]", tokenInfo(content.node.get()), true });
continue;
}
@@ -365,7 +380,7 @@
if (tokensInCurrentParagraph.isEmpty())
startOfCurrentParagraph = Position(&textNode, startOfCurrentLine);
- tokensInCurrentParagraph.append(ManipulationToken { m_tokenIdentifier.generate(), stringUntilEndOfLine, exclusionRuleMatcher.isExcluded(content.node.get()) });
+ tokensInCurrentParagraph.append(ManipulationToken { m_tokenIdentifier.generate(), stringUntilEndOfLine, tokenInfo(&textNode), exclusionRuleMatcher.isExcluded(content.node.get()) });
}
if (!tokensInCurrentParagraph.isEmpty()) {
@@ -385,7 +400,7 @@
startOfCurrentParagraph = iterator.startPosition();
}
endOfCurrentParagraph = iterator.endPosition();
- tokensInCurrentParagraph.append(ManipulationToken { m_tokenIdentifier.generate(), remainingText.toString(), exclusionRuleMatcher.isExcluded(content.node.get()) });
+ tokensInCurrentParagraph.append(ManipulationToken { m_tokenIdentifier.generate(), remainingText.toString(), tokenInfo(content.node.get()), exclusionRuleMatcher.isExcluded(content.node.get()) });
}
}
Modified: trunk/Source/WebCore/editing/TextManipulationController.h (260864 => 260865)
--- trunk/Source/WebCore/editing/TextManipulationController.h 2020-04-29 04:26:12 UTC (rev 260864)
+++ trunk/Source/WebCore/editing/TextManipulationController.h 2020-04-29 05:16:23 UTC (rev 260865)
@@ -48,9 +48,19 @@
enum TokenIdentifierType { };
using TokenIdentifier = ObjectIdentifier<TokenIdentifierType>;
+ struct ManipulationTokenInfo {
+ String tagName;
+ String roleAttribute;
+ URL documentURL;
+
+ template<class Encoder> void encode(Encoder&) const;
+ template<class Decoder> static Optional<ManipulationTokenInfo> decode(Decoder&);
+ };
+
struct ManipulationToken {
TokenIdentifier identifier;
String content;
+ Optional<ManipulationTokenInfo> info;
bool isExcluded { false };
template<class Encoder> void encode(Encoder&) const;
@@ -158,9 +168,33 @@
};
template<class Encoder>
+void TextManipulationController::ManipulationTokenInfo::encode(Encoder& encoder) const
+{
+ encoder << tagName;
+ encoder << roleAttribute;
+ encoder << documentURL;
+}
+
+template<class Decoder>
+Optional<TextManipulationController::ManipulationTokenInfo> TextManipulationController::ManipulationTokenInfo::decode(Decoder& decoder)
+{
+ ManipulationTokenInfo result;
+ if (!decoder.decode(result.tagName))
+ return WTF::nullopt;
+
+ if (!decoder.decode(result.roleAttribute))
+ return WTF::nullopt;
+
+ if (!decoder.decode(result.documentURL))
+ return WTF::nullopt;
+
+ return result;
+}
+
+template<class Encoder>
void TextManipulationController::ManipulationToken::encode(Encoder& encoder) const
{
- encoder << identifier << content << isExcluded;
+ encoder << identifier << content << info << isExcluded;
}
template<class Decoder>
@@ -171,6 +205,8 @@
return WTF::nullopt;
if (!decoder.decode(result.content))
return WTF::nullopt;
+ if (!decoder.decode(result.info))
+ return WTF::nullopt;
if (!decoder.decode(result.isExcluded))
return WTF::nullopt;
return result;
Modified: trunk/Source/WebKit/ChangeLog (260864 => 260865)
--- trunk/Source/WebKit/ChangeLog 2020-04-29 04:26:12 UTC (rev 260864)
+++ trunk/Source/WebKit/ChangeLog 2020-04-29 05:16:23 UTC (rev 260865)
@@ -1,3 +1,27 @@
+2020-04-28 Wenson Hsieh <[email protected]>
+
+ [Text manipulation] Add a userInfo dictionary to _WKTextManipulationToken
+ https://bugs.webkit.org/show_bug.cgi?id=211151
+ <rdar://problem/62329534>
+
+ Reviewed by Darin Adler.
+
+ * UIProcess/API/Cocoa/WKWebView.mm:
+ (createUserInfo):
+ (-[WKWebView _startTextManipulationsWithConfiguration:completion:]):
+ (-[WKWebView _completeTextManipulation:completion:]):
+ (-[WKWebView _completeTextManipulationForItems:completion:]):
+ * UIProcess/API/Cocoa/_WKTextManipulationToken.h:
+ * UIProcess/API/Cocoa/_WKTextManipulationToken.mm:
+ (-[_WKTextManipulationToken setUserInfo:]):
+ (-[_WKTextManipulationToken userInfo]):
+
+ Add a new `userInfo` dictionary to `_WKTextManipulationToken`, which contains several named
+ `NSString` keys.
+
+ (-[_WKTextManipulationToken isEqualToTextManipulationToken:includingContentEquality:]):
+ (-[_WKTextManipulationToken _descriptionPreservingPrivacy:]):
+
2020-04-28 David Kilzer <[email protected]>
REGRESSION (r260407): Over-release of NSGraphicsContext in WebKit::convertPlatformImageToBitmap()
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm (260864 => 260865)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm 2020-04-29 04:26:12 UTC (rev 260864)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm 2020-04-29 05:16:23 UTC (rev 260865)
@@ -1606,6 +1606,22 @@
_textManipulationDelegate = delegate;
}
+static RetainPtr<NSDictionary<NSString *, id>> createUserInfo(const Optional<WebCore::TextManipulationController::ManipulationTokenInfo>& info)
+{
+ if (!info)
+ return { };
+
+ auto result = adoptNS([[NSMutableDictionary alloc] initWithCapacity:3]);
+ if (!info->documentURL.isNull())
+ [result setObject:(NSURL *)info->documentURL forKey:_WKTextManipulationTokenUserInfoDocumentURLKey];
+ if (!info->tagName.isNull())
+ [result setObject:(NSString *)info->tagName forKey:_WKTextManipulationTokenUserInfoTagNameKey];
+ if (!info->roleAttribute.isNull())
+ [result setObject:(NSString *)info->roleAttribute forKey:_WKTextManipulationTokenUserInfoRoleAttributeKey];
+
+ return result;
+}
+
- (void)_startTextManipulationsWithConfiguration:(_WKTextManipulationConfiguration *)configuration completion:(void(^)())completionHandler
{
using ExclusionRule = WebCore::TextManipulationController::ExclusionRule;
@@ -1643,6 +1659,7 @@
[wkToken setIdentifier:String::number(token.identifier.toUInt64())];
[wkToken setContent:token.content];
[wkToken setExcluded:token.isExcluded];
+ [wkToken setUserInfo:createUserInfo(token.info).get()];
return wkToken;
});
return adoptNS([[_WKTextManipulationItem alloc] initWithIdentifier:String::number(item.identifier.toUInt64()) tokens:tokens.get()]);
@@ -1680,7 +1697,7 @@
Vector<WebCore::TextManipulationController::ManipulationToken> tokens;
for (_WKTextManipulationToken *wkToken in item.tokens)
- tokens.append(WebCore::TextManipulationController::ManipulationToken { coreTextManipulationTokenIdentifierFromString(wkToken.identifier), wkToken.content });
+ tokens.append(WebCore::TextManipulationController::ManipulationToken { coreTextManipulationTokenIdentifierFromString(wkToken.identifier), wkToken.content, WTF::nullopt });
Vector<WebCore::TextManipulationController::ManipulationItem> coreItems;
coreItems.reserveInitialCapacity(1);
@@ -1739,7 +1756,7 @@
Vector<WebCore::TextManipulationController::ManipulationToken> coreTokens;
coreTokens.reserveInitialCapacity(wkItem.tokens.count);
for (_WKTextManipulationToken *wkToken in wkItem.tokens)
- coreTokens.uncheckedAppend(WebCore::TextManipulationController::ManipulationToken { coreTextManipulationTokenIdentifierFromString(wkToken.identifier), wkToken.content });
+ coreTokens.uncheckedAppend(WebCore::TextManipulationController::ManipulationToken { coreTextManipulationTokenIdentifierFromString(wkToken.identifier), wkToken.content, WTF::nullopt });
coreItems.uncheckedAppend(WebCore::TextManipulationController::ManipulationItem { coreTextManipulationItemIdentifierFromString(wkItem.identifier), WTFMove(coreTokens) });
}
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/_WKTextManipulationToken.h (260864 => 260865)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/_WKTextManipulationToken.h 2020-04-29 04:26:12 UTC (rev 260864)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/_WKTextManipulationToken.h 2020-04-29 05:16:23 UTC (rev 260865)
@@ -28,6 +28,10 @@
NS_ASSUME_NONNULL_BEGIN
+WK_EXTERN NSString * const _WKTextManipulationTokenUserInfoDocumentURLKey WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
+WK_EXTERN NSString * const _WKTextManipulationTokenUserInfoTagNameKey WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
+WK_EXTERN NSString * const _WKTextManipulationTokenUserInfoRoleAttributeKey WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
+
WK_CLASS_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA))
@interface _WKTextManipulationToken : NSObject
@@ -38,6 +42,8 @@
- (BOOL)isEqualToTextManipulationToken:(nullable _WKTextManipulationToken *)otherToken includingContentEquality:(BOOL)includingContentEquality;
@property (nonatomic, copy, readonly) NSString *debugDescription;
+@property (nonatomic, nullable, copy) NSDictionary<NSString *, id> *userInfo;
+
@end
NS_ASSUME_NONNULL_END
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/_WKTextManipulationToken.mm (260864 => 260865)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/_WKTextManipulationToken.mm 2020-04-29 04:26:12 UTC (rev 260864)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/_WKTextManipulationToken.mm 2020-04-29 05:16:23 UTC (rev 260865)
@@ -26,8 +26,16 @@
#import "config.h"
#import "_WKTextManipulationToken.h"
-@implementation _WKTextManipulationToken
+#import <wtf/RetainPtr.h>
+NSString * const _WKTextManipulationTokenUserInfoDocumentURLKey = @"_WKTextManipulationTokenUserInfoDocumentURLKey";
+NSString * const _WKTextManipulationTokenUserInfoTagNameKey = @"_WKTextManipulationTokenUserInfoTagNameKey";
+NSString * const _WKTextManipulationTokenUserInfoRoleAttributeKey = @"_WKTextManipulationTokenUserInfoRoleAttributeKey";
+
+@implementation _WKTextManipulationToken {
+ RetainPtr<NSDictionary<NSString *, id>> _userInfo;
+}
+
- (void)dealloc
{
[_identifier release];
@@ -38,6 +46,19 @@
[super dealloc];
}
+- (void)setUserInfo:(NSDictionary<NSString *, id> *)userInfo
+{
+ if (userInfo == _userInfo || [_userInfo isEqual:userInfo])
+ return;
+
+ _userInfo = adoptNS(userInfo.copy);
+}
+
+- (NSDictionary<NSString *, id> *)userInfo
+{
+ return _userInfo.get();
+}
+
static BOOL isEqualOrBothNil(id a, id b)
{
if (a == b)
@@ -65,8 +86,9 @@
BOOL equalIdentifiers = isEqualOrBothNil(self.identifier, otherToken.identifier);
BOOL equalExclusion = self.isExcluded == otherToken.isExcluded;
BOOL equalContent = !includingContentEquality || isEqualOrBothNil(self.content, otherToken.content);
+ BOOL equalUserInfo = isEqualOrBothNil(self.userInfo, otherToken.userInfo);
- return equalIdentifiers && equalExclusion && equalContent;
+ return equalIdentifiers && equalExclusion && equalContent && equalUserInfo;
}
- (NSString *)description
@@ -85,7 +107,7 @@
if (preservePrivacy)
[description appendFormat:@"; content length = %lu", (unsigned long)self.content.length];
else
- [description appendFormat:@"; content = %@", self.content];
+ [description appendFormat:@"; content = %@; user info = %@", self.content, self.userInfo];
[description appendString:@">"];
Modified: trunk/Tools/ChangeLog (260864 => 260865)
--- trunk/Tools/ChangeLog 2020-04-29 04:26:12 UTC (rev 260864)
+++ trunk/Tools/ChangeLog 2020-04-29 05:16:23 UTC (rev 260865)
@@ -1,3 +1,15 @@
+2020-04-28 Wenson Hsieh <[email protected]>
+
+ [Text manipulation] Add a userInfo dictionary to _WKTextManipulationToken
+ https://bugs.webkit.org/show_bug.cgi?id=211151
+ <rdar://problem/62329534>
+
+ Reviewed by Darin Adler.
+
+ Add a new API test to check the userInfo dictionary on text manipulation tokens.
+
+ * TestWebKitAPI/Tests/WebKitCocoa/TextManipulation.mm:
+
2020-04-28 David Kilzer <[email protected]>
check-webkit-style should suggest CheckedSize for Checked<size_t, RecordOverflow>
Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/TextManipulation.mm (260864 => 260865)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/TextManipulation.mm 2020-04-29 04:26:12 UTC (rev 260864)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/TextManipulation.mm 2020-04-29 05:16:23 UTC (rev 260865)
@@ -704,6 +704,59 @@
EXPECT_WK_STREQ("Garply", items[3].tokens[0].content);
}
+TEST(TextManipulation, StartTextManipulationExtractsUserInfo)
+{
+ auto delegate = adoptNS([[TextManipulationDelegate alloc] init]);
+ auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 400, 400)]);
+ [webView _setTextManipulationDelegate:delegate.get()];
+
+ [webView synchronouslyLoadHTMLString:@"<!DOCTYPE html>"
+ "<body>"
+ " <title>This is a test</title>"
+ " <p>First</p>"
+ " <div role='button'>Second</div>"
+ " <span>Third</span>"
+ "</body>"];
+
+ done = false;
+ [webView _startTextManipulationsWithConfiguration:nil completion:^{
+ done = true;
+ }];
+ TestWebKitAPI::Util::run(&done);
+
+ auto items = [delegate items];
+ EXPECT_EQ(items.count, 4UL);
+ EXPECT_EQ(items[0].tokens.count, 1UL);
+ EXPECT_EQ(items[1].tokens.count, 1UL);
+ EXPECT_EQ(items[2].tokens.count, 1UL);
+ EXPECT_EQ(items[3].tokens.count, 1UL);
+ EXPECT_WK_STREQ("This is a test", items[0].tokens[0].content);
+ EXPECT_WK_STREQ("First", items[1].tokens[0].content);
+ EXPECT_WK_STREQ("Second", items[2].tokens[0].content);
+ EXPECT_WK_STREQ("Third", items[3].tokens[0].content);
+ {
+ auto userInfo = items[0].tokens[0].userInfo;
+ EXPECT_WK_STREQ("TestWebKitAPI.resources", [(NSURL *)userInfo[_WKTextManipulationTokenUserInfoDocumentURLKey] lastPathComponent]);
+ EXPECT_WK_STREQ("TITLE", (NSString *)userInfo[_WKTextManipulationTokenUserInfoTagNameKey]);
+ }
+ {
+ auto userInfo = items[1].tokens[0].userInfo;
+ EXPECT_WK_STREQ("TestWebKitAPI.resources", [(NSURL *)userInfo[_WKTextManipulationTokenUserInfoDocumentURLKey] lastPathComponent]);
+ EXPECT_WK_STREQ("P", (NSString *)userInfo[_WKTextManipulationTokenUserInfoTagNameKey]);
+ }
+ {
+ auto userInfo = items[2].tokens[0].userInfo;
+ EXPECT_WK_STREQ("TestWebKitAPI.resources", [(NSURL *)userInfo[_WKTextManipulationTokenUserInfoDocumentURLKey] lastPathComponent]);
+ EXPECT_WK_STREQ("DIV", (NSString *)userInfo[_WKTextManipulationTokenUserInfoTagNameKey]);
+ EXPECT_WK_STREQ("button", (NSString *)userInfo[_WKTextManipulationTokenUserInfoRoleAttributeKey]);
+ }
+ {
+ auto userInfo = items[3].tokens[0].userInfo;
+ EXPECT_WK_STREQ("TestWebKitAPI.resources", [(NSURL *)userInfo[_WKTextManipulationTokenUserInfoDocumentURLKey] lastPathComponent]);
+ EXPECT_WK_STREQ("SPAN", (NSString *)userInfo[_WKTextManipulationTokenUserInfoTagNameKey]);
+ }
+}
+
struct Token {
NSString *identifier;
NSString *content;