Skip to content
Permalink
Browse files
Add AssistedNodeInformation plumbing for form control placeholder tex…
…t and label text

https://bugs.webkit.org/show_bug.cgi?id=183802
<rdar://problem/38686273>

Reviewed by Tim Horton.

Source/WebKit:

Surfaces some additional information about the currently focused element to the input delegate in the UI process.
See comments below for more details.

Test: WebKit.FocusedElementInfo

* Shared/AssistedNodeInformation.cpp:
(WebKit::AssistedNodeInformation::encode const):
(WebKit::AssistedNodeInformation::decode):
* Shared/AssistedNodeInformation.h:

Add `placeholder` and `label` to AssistedNodeInformation, which capture the value of the placeholder attribute
and the text of the first associated label element for the focused form control. Also add boilerplate encoder/
decoder support for these members.

* UIProcess/API/Cocoa/_WKFocusedElementInfo.h:

Augment _WKFocusedElementInfo to include placeholder and label.

* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKFocusedElementInfo initWithAssistedNodeInformation:isUserInitiated:userObject:]):
(-[WKFocusedElementInfo label]):
(-[WKFocusedElementInfo placeholder]):
* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::WebPage::getAssistedNodeInformation):

For input elements and textareas, set the placeholder to the value of the placeholder attribute. For all
elements with associated labels, grab the inner text of the first label that is not empty, ignoring all labels
that are `display: none` (i.e. not being rendered).

Tools:

Adds a new API test to exercise new placeholder and label SPI on _WKFocusedFormElement.

* TestWebKitAPI/Tests/WebKitCocoa/_WKInputDelegate.mm:
(-[InputDelegate _webView:focusShouldStartInputSession:]):
(-[InputDelegate shouldStartInputSessionHandler]):
(-[InputDelegate setShouldStartInputSessionHandler:]):
(TEST):
(-[FormSubmissionDelegate webView:startURLSchemeTask:]): Deleted.
(-[FormSubmissionDelegate webView:stopURLSchemeTask:]): Deleted.
(-[FormSubmissionDelegate _webView:willSubmitFormValues:userObject:submissionHandler:]): Deleted.


Canonical link: https://commits.webkit.org/199427@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@229783 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
whsieh committed Mar 21, 2018
1 parent c3aabcb commit 10527f00eaf0746accd4d038b69bf35f7b53b797
@@ -1,3 +1,40 @@
2018-03-20 Wenson Hsieh <wenson_hsieh@apple.com>

Add AssistedNodeInformation plumbing for form control placeholder text and label text
https://bugs.webkit.org/show_bug.cgi?id=183802
<rdar://problem/38686273>

Reviewed by Tim Horton.

Surfaces some additional information about the currently focused element to the input delegate in the UI process.
See comments below for more details.

Test: WebKit.FocusedElementInfo

* Shared/AssistedNodeInformation.cpp:
(WebKit::AssistedNodeInformation::encode const):
(WebKit::AssistedNodeInformation::decode):
* Shared/AssistedNodeInformation.h:

Add `placeholder` and `label` to AssistedNodeInformation, which capture the value of the placeholder attribute
and the text of the first associated label element for the focused form control. Also add boilerplate encoder/
decoder support for these members.

* UIProcess/API/Cocoa/_WKFocusedElementInfo.h:

Augment _WKFocusedElementInfo to include placeholder and label.

* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKFocusedElementInfo initWithAssistedNodeInformation:isUserInitiated:userObject:]):
(-[WKFocusedElementInfo label]):
(-[WKFocusedElementInfo placeholder]):
* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::WebPage::getAssistedNodeInformation):

For input elements and textareas, set the placeholder to the value of the placeholder attribute. For all
elements with associated labels, grab the inner text of the first label that is not empty, ignoring all labels
that are `display: none` (i.e. not being rendered).

2018-03-20 Brady Eidson <beidson@apple.com>

First piece of process swapping on navigation.
@@ -89,6 +89,8 @@ void AssistedNodeInformation::encode(IPC::Encoder& encoder) const
encoder << acceptsAutofilledLoginCredentials;
encoder << representingPageURL;
encoder.encodeEnum(autofillFieldName);
encoder << placeholder;
encoder << label;
encoder << assistedNodeIdentifier;
}

@@ -172,6 +174,12 @@ bool AssistedNodeInformation::decode(IPC::Decoder& decoder, AssistedNodeInformat
if (!decoder.decodeEnum(result.autofillFieldName))
return false;

if (!decoder.decode(result.placeholder))
return false;

if (!decoder.decode(result.label))
return false;

if (!decoder.decode(result.assistedNodeIdentifier))
return false;

@@ -113,6 +113,8 @@ struct AssistedNodeInformation {
bool acceptsAutofilledLoginCredentials { false };
WebCore::URL representingPageURL;
WebCore::AutofillFieldName autofillFieldName { WebCore::AutofillFieldName::None };
String placeholder;
String label;

uint64_t assistedNodeIdentifier { 0 };

@@ -68,6 +68,12 @@ typedef NS_ENUM(NSInteger, WKInputType) {
/* The value of the input at the time it was focused. */
@property (nonatomic, readonly, copy) NSString *value;

/* The placeholder text of the input. */
@property (nonatomic, readonly, copy) NSString *placeholder;

/* The text of a label element associated with the input. */
@property (nonatomic, readonly, copy) NSString *label;

/**
* Whether the element was focused due to user interaction. NO indicates that
* the element was focused programmatically, e.g. by calling focus() in JavaScript
@@ -407,6 +407,8 @@ @implementation WKFocusedElementInfo {
RetainPtr<NSString> _value;
BOOL _isUserInitiated;
RetainPtr<NSObject <NSSecureCoding>> _userObject;
RetainPtr<NSString> _placeholder;
RetainPtr<NSString> _label;
}

- (instancetype)initWithAssistedNodeInformation:(const AssistedNodeInformation&)information isUserInitiated:(BOOL)isUserInitiated userObject:(NSObject <NSSecureCoding> *)userObject
@@ -473,6 +475,8 @@ - (instancetype)initWithAssistedNodeInformation:(const AssistedNodeInformation&)
_value = information.value;
_isUserInitiated = isUserInitiated;
_userObject = userObject;
_placeholder = information.placeholder;
_label = information.label;
return self;
}

@@ -495,6 +499,17 @@ - (BOOL)isUserInitiated
{
return _userObject.get();
}

- (NSString *)label
{
return _label.get();
}

- (NSString *)placeholder
{
return _placeholder.get();
}

@end

#if ENABLE(DRAG_SUPPORT)
@@ -91,6 +91,7 @@
#import <WebCore/MainFrame.h>
#import <WebCore/MediaSessionManagerIOS.h>
#import <WebCore/Node.h>
#import <WebCore/NodeList.h>
#import <WebCore/NotImplemented.h>
#import <WebCore/Page.h>
#import <WebCore/Pasteboard.h>
@@ -2749,6 +2750,22 @@ static inline bool hasAssistableElement(Node* startNode, Page& page, bool isForw
information.hasPreviousNode = hasAssistableElement(m_assistedNode.get(), *m_page, false);
information.assistedNodeIdentifier = m_currentAssistedNodeIdentifier;

if (is<LabelableElement>(*m_assistedNode)) {
auto labels = downcast<LabelableElement>(*m_assistedNode).labels();
Vector<Ref<Element>> associatedLabels;
for (unsigned index = 0; index < labels->length(); ++index) {
if (is<Element>(labels->item(index)) && labels->item(index)->renderer())
associatedLabels.append(downcast<Element>(*labels->item(index)));
}
for (auto& labelElement : associatedLabels) {
auto text = labelElement->innerText();
if (!text.isEmpty()) {
information.label = WTFMove(text);
break;
}
}
}

if (is<HTMLSelectElement>(*m_assistedNode)) {
HTMLSelectElement& element = downcast<HTMLSelectElement>(*m_assistedNode);
information.elementType = InputType::Select;
@@ -2779,6 +2796,7 @@ static inline bool hasAssistableElement(Node* startNode, Page& page, bool isForw
information.isReadOnly = element.isReadOnly();
information.value = element.value();
information.autofillFieldName = WebCore::toAutofillFieldName(element.autofillData().fieldName);
information.placeholder = element.attributeWithoutSynchronization(HTMLNames::placeholderAttr);
} else if (is<HTMLInputElement>(*m_assistedNode)) {
HTMLInputElement& element = downcast<HTMLInputElement>(*m_assistedNode);
HTMLFormElement* form = element.form();
@@ -2788,6 +2806,7 @@ static inline bool hasAssistableElement(Node* startNode, Page& page, bool isForw
information.representingPageURL = element.document().urlForBindings();
information.autocapitalizeType = element.autocapitalizeType();
information.isAutocorrect = element.shouldAutocorrect();
information.placeholder = element.attributeWithoutSynchronization(HTMLNames::placeholderAttr);
if (element.isPasswordField())
information.elementType = InputType::Password;
else if (element.isSearchField())
@@ -1,3 +1,22 @@
2018-03-20 Wenson Hsieh <wenson_hsieh@apple.com>

Add AssistedNodeInformation plumbing for form control placeholder text and label text
https://bugs.webkit.org/show_bug.cgi?id=183802
<rdar://problem/38686273>

Reviewed by Tim Horton.

Adds a new API test to exercise new placeholder and label SPI on _WKFocusedFormElement.

* TestWebKitAPI/Tests/WebKitCocoa/_WKInputDelegate.mm:
(-[InputDelegate _webView:focusShouldStartInputSession:]):
(-[InputDelegate shouldStartInputSessionHandler]):
(-[InputDelegate setShouldStartInputSessionHandler:]):
(TEST):
(-[FormSubmissionDelegate webView:startURLSchemeTask:]): Deleted.
(-[FormSubmissionDelegate webView:stopURLSchemeTask:]): Deleted.
(-[FormSubmissionDelegate _webView:willSubmitFormValues:userObject:submissionHandler:]): Deleted.

2018-03-20 Basuke Suzuki <Basuke.Suzuki@sony.com>

[WinCairo] Fix to run-webkit-httpd from native Windows.
@@ -27,19 +27,26 @@

#import "PlatformUtilities.h"
#import "Test.h"
#import "TestWKWebView.h"
#import <WebKit/WKWebViewPrivate.h>
#import <WebKit/_WKFocusedElementInfo.h>
#import <WebKit/_WKFormInputSession.h>
#import <WebKit/_WKInputDelegate.h>
#import <wtf/BlockPtr.h>
#import <wtf/RetainPtr.h>

#if WK_API_ENABLED

static bool done;
static bool willSubmitFormValuesCalled;

@interface FormSubmissionDelegate : NSObject <_WKInputDelegate, WKURLSchemeHandler>
@interface InputDelegate : NSObject <_WKInputDelegate, WKURLSchemeHandler>
@property (nonatomic, copy) BOOL(^shouldStartInputSessionHandler)(id <_WKFocusedElementInfo>);
@end

@implementation FormSubmissionDelegate
@implementation InputDelegate {
BlockPtr<BOOL(id <_WKFocusedElementInfo>)> _shouldStartInputSessionHandler;
}

- (void)webView:(WKWebView *)webView startURLSchemeTask:(id <WKURLSchemeTask>)task
{
@@ -64,11 +71,28 @@ - (void)_webView:(WKWebView *)webView willSubmitFormValues:(NSDictionary *)value
submissionHandler();
}

- (BOOL)_webView:(WKWebView *)webView focusShouldStartInputSession:(id <_WKFocusedElementInfo>)info
{
if (_shouldStartInputSessionHandler)
return _shouldStartInputSessionHandler(info);
return [info isUserInitiated];
}

- (BOOL(^)(id <_WKFocusedElementInfo>))shouldStartInputSessionHandler
{
return _shouldStartInputSessionHandler.get();
}

- (void)setShouldStartInputSessionHandler:(BOOL(^)(id <_WKFocusedElementInfo>))handler
{
_shouldStartInputSessionHandler = makeBlockPtr(handler);
}

@end

TEST(WebKit, FormSubmission)
{
auto delegate = adoptNS([[FormSubmissionDelegate alloc] init]);
auto delegate = adoptNS([[InputDelegate alloc] init]);
auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
[configuration setURLSchemeHandler:delegate.get() forURLScheme:@"test"];
auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
@@ -81,6 +105,47 @@ - (void)_webView:(WKWebView *)webView willSubmitFormValues:(NSDictionary *)value
TestWebKitAPI::Util::run(&done);
}

#if PLATFORM(IOS)

TEST(WebKit, FocusedElementInfo)
{
auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
auto delegate = adoptNS([[InputDelegate alloc] init]);
[webView _setInputDelegate:delegate.get()];

__block RetainPtr<id <_WKFocusedElementInfo>> currentElement;
[delegate setShouldStartInputSessionHandler:^BOOL(id<_WKFocusedElementInfo> element) {
currentElement = element;
return NO;
}];

[webView synchronouslyLoadHTMLString:@"<label for='foo'>bar</label><input id='foo'>"];
[webView stringByEvaluatingJavaScript:@"foo.focus()"];
[webView waitForNextPresentationUpdate];
EXPECT_WK_STREQ("", [currentElement placeholder]);
EXPECT_WK_STREQ("bar", [currentElement label]);

[webView synchronouslyLoadHTMLString:@"<input placeholder='bar'>"];
[webView stringByEvaluatingJavaScript:@"document.querySelector('input').focus()"];
[webView waitForNextPresentationUpdate];
EXPECT_WK_STREQ("bar", [currentElement placeholder]);
EXPECT_WK_STREQ("", [currentElement label]);

[webView synchronouslyLoadHTMLString:@"<label for='baz'>garply</label><select id='baz'></select>"];
[webView stringByEvaluatingJavaScript:@"baz.focus()"];
[webView waitForNextPresentationUpdate];
EXPECT_WK_STREQ("", [currentElement placeholder]);
EXPECT_WK_STREQ("garply", [currentElement label]);

[webView synchronouslyLoadHTMLString:@"<label for='foo' style='display: none'>bar</label><label for='foo'></label><input id='foo'><label for='foo'>garply</label>"];
[webView stringByEvaluatingJavaScript:@"foo.focus()"];
[webView waitForNextPresentationUpdate];
EXPECT_WK_STREQ("", [currentElement placeholder]);
EXPECT_WK_STREQ("garply", [currentElement label]);
}

#endif // PLATFORM(IOS)

#endif // WK_API_ENABLED


0 comments on commit 10527f0

Please sign in to comment.