Commit 7f9ae285 authored by Maria Kazinova's avatar Maria Kazinova Committed by Commit Bot

[iOS] Using numeric renderer IDs for Autofill form clearing.

Bug: 1075444, 1131038
Change-Id: Id5aa1c9d1e3a18d432d460c1a45878a945d018c1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2435092
Commit-Queue: Maria Kazinova <kazinova@google.com>
Reviewed-by: default avatarOlivier Robin <olivierrobin@chromium.org>
Reviewed-by: default avatarVadym Doroshenko  <dvadym@chromium.org>
Reviewed-by: default avatarJohn Wu <jzw@chromium.org>
Cr-Commit-Position: refs/heads/master@{#812306}
parent e4928121
...@@ -455,7 +455,9 @@ autofillManagerFromWebState:(web::WebState*)webState ...@@ -455,7 +455,9 @@ autofillManagerFromWebState:(web::WebState*)webState
__weak AutofillAgent* weakSelf = self; __weak AutofillAgent* weakSelf = self;
[_jsAutofillManager [_jsAutofillManager
clearAutofilledFieldsForFormName:formName clearAutofilledFieldsForFormName:formName
formUniqueID:uniqueFormID
fieldIdentifier:fieldIdentifier fieldIdentifier:fieldIdentifier
fieldUniqueID:uniqueFieldID
inFrame:frame inFrame:frame
completionHandler:^(NSString* jsonString) { completionHandler:^(NSString* jsonString) {
AutofillAgent* strongSelf = weakSelf; AutofillAgent* strongSelf = weakSelf;
......
...@@ -13,15 +13,29 @@ ...@@ -13,15 +13,29 @@
@interface FakeJSAutofillManager : JsAutofillManager @interface FakeJSAutofillManager : JsAutofillManager
// The name of the form that was most recently passed to // The name of the form that was most recently passed to
// |clearAutofilledFieldsForFormName:fieldIdentifier:inFrame:completionHandler:| // |clearAutofilledFieldsForFormName:formUniqueID:fieldIdentifier:
// fieldUniqueID:inFrame:completionHandler:|
@property(nonatomic, copy, readonly) NSString* lastClearedFormName; @property(nonatomic, copy, readonly) NSString* lastClearedFormName;
// The renderer ID of the form that was most recently passed to
// |clearAutofilledFieldsForFormName:formUniqueID:fieldIdentifier:
// fieldUniqueID:inFrame:completionHandler:|
@property(nonatomic, readonly) autofill::FormRendererId lastClearedFormUniqueID;
// The field identifier that was most recently passed to // The field identifier that was most recently passed to
// |clearAutofilledFieldsForFormName:fieldIdentifier:inFrame:completionHandler:| // |clearAutofilledFieldsForFormName:formUniqueID:fieldIdentifier:
// fieldUniqueID:inFrame:completionHandler:|
@property(nonatomic, copy, readonly) NSString* lastClearedFieldIdentifier; @property(nonatomic, copy, readonly) NSString* lastClearedFieldIdentifier;
// The renderer ID of the field that was most recently passed to
// |clearAutofilledFieldsForFormName:formUniqueID:fieldIdentifier:
// fieldUniqueID:inFrame:completionHandler:|
@property(nonatomic, readonly)
autofill::FieldRendererId lastClearedFieldUniqueID;
// The field identifier that was most recently passed to // The field identifier that was most recently passed to
// |clearAutofilledFieldsForFormName:fieldIdentifier:inFrame:completionHandler:| // |clearAutofilledFieldsForFormName:formUniqueID:fieldIdentifier:
// fieldUniqueID:inFrame:completionHandler:|
@property(nonatomic, copy, readonly) NSString* lastClearedFrameIdentifier; @property(nonatomic, copy, readonly) NSString* lastClearedFrameIdentifier;
@end @end
......
...@@ -18,17 +18,23 @@ ...@@ -18,17 +18,23 @@
@implementation FakeJSAutofillManager @implementation FakeJSAutofillManager
@synthesize lastClearedFormName = _lastClearedFormName; @synthesize lastClearedFormName = _lastClearedFormName;
@synthesize lastClearedFormUniqueID = _lastClearedFormUniqueID;
@synthesize lastClearedFieldIdentifier = _lastClearedFieldIdentifier; @synthesize lastClearedFieldIdentifier = _lastClearedFieldIdentifier;
@synthesize lastClearedFieldUniqueID = _lastClearedFieldUniqueID;
@synthesize lastClearedFrameIdentifier = _lastClearedFrameIdentifier; @synthesize lastClearedFrameIdentifier = _lastClearedFrameIdentifier;
- (void)clearAutofilledFieldsForFormName:(NSString*)formName - (void)
fieldIdentifier:(NSString*)fieldIdentifier clearAutofilledFieldsForFormName:(NSString*)formName
inFrame:(web::WebFrame*)frame formUniqueID:(autofill::FormRendererId)formUniqueID
completionHandler: fieldIdentifier:(NSString*)fieldIdentifier
(void (^)(NSString*))completionHandler { fieldUniqueID:(autofill::FieldRendererId)fieldUniqueID
inFrame:(web::WebFrame*)frame
completionHandler:(void (^)(NSString*))completionHandler {
base::PostTask(FROM_HERE, {web::WebThread::UI}, base::BindOnce(^{ base::PostTask(FROM_HERE, {web::WebThread::UI}, base::BindOnce(^{
_lastClearedFormName = [formName copy]; _lastClearedFormName = [formName copy];
_lastClearedFormUniqueID = formUniqueID;
_lastClearedFieldIdentifier = [fieldIdentifier copy]; _lastClearedFieldIdentifier = [fieldIdentifier copy];
_lastClearedFieldUniqueID = fieldUniqueID;
_lastClearedFrameIdentifier = _lastClearedFrameIdentifier =
frame ? base::SysUTF8ToNSString(frame->GetFrameId()) frame ? base::SysUTF8ToNSString(frame->GetFrameId())
: nil; : nil;
......
...@@ -36,8 +36,8 @@ class WebFrame; ...@@ -36,8 +36,8 @@ class WebFrame;
// Fills a number of fields in the same named form for full-form Autofill. // Fills a number of fields in the same named form for full-form Autofill.
// Applies Autofill CSS (i.e. yellow background) to filled elements. // Applies Autofill CSS (i.e. yellow background) to filled elements.
// Only empty fields will be filled, except that field named // Only empty fields will be filled, except that field named
// |forceFillFieldIdentifier| will always be filled even if non-empty. // Field identified by |forceFillFieldIdentifier|/|forceFillFieldUniqueID| will
// |forceFillFieldIdentifier| may be null. // always be filled even if non-empty. |forceFillFieldIdentifier| may be null.
// Fields must be contained in |frame|. // Fields must be contained in |frame|.
// |completionHandler| is called after the forms are filled with the JSON // |completionHandler| is called after the forms are filled with the JSON
// string containing pairs of unique renderer ids of filled fields and // string containing pairs of unique renderer ids of filled fields and
...@@ -52,14 +52,17 @@ class WebFrame; ...@@ -52,14 +52,17 @@ class WebFrame;
// currently autofilled are not modified. Field contents are cleared, and // currently autofilled are not modified. Field contents are cleared, and
// Autofill flag and styling are removed. 'change' events are sent for fields // Autofill flag and styling are removed. 'change' events are sent for fields
// whose contents changed. // whose contents changed.
// |fieldIdentifier| identifies the field that initiated the clear action. // |fieldIdentifier|/|fieldUniqueID| identify the field that initiated the clear
// |completionHandler| is called after the forms are filled with the JSON // action. |completionHandler| is called after the forms are filled with the
// string containing a list of unique renderer ids of cleared fields. // JSON string containing a list of unique renderer ids of cleared fields.
// |completionHandler| cannot be nil. // |completionHandler| cannot be nil.
- (void)clearAutofilledFieldsForFormName:(NSString*)formName - (void)
fieldIdentifier:(NSString*)fieldIdentifier clearAutofilledFieldsForFormName:(NSString*)formName
inFrame:(web::WebFrame*)frame formUniqueID:(autofill::FormRendererId)formRendererID
completionHandler:(void (^)(NSString*))completionHandler; fieldIdentifier:(NSString*)fieldIdentifier
fieldUniqueID:(autofill::FieldRendererId)fieldRendererID
inFrame:(web::WebFrame*)frame
completionHandler:(void (^)(NSString*))completionHandler;
// Marks up the form with autofill field prediction data (diagnostic tool). // Marks up the form with autofill field prediction data (diagnostic tool).
- (void)fillPredictionData:(std::unique_ptr<base::Value>)data - (void)fillPredictionData:(std::unique_ptr<base::Value>)data
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#endif #endif
using autofill::FieldRendererId; using autofill::FieldRendererId;
using autofill::FormRendererId;
@implementation JsAutofillManager @implementation JsAutofillManager
...@@ -128,14 +129,27 @@ using autofill::FieldRendererId; ...@@ -128,14 +129,27 @@ using autofill::FieldRendererId;
} }
- (void)clearAutofilledFieldsForFormName:(NSString*)formName - (void)clearAutofilledFieldsForFormName:(NSString*)formName
formUniqueID:(FormRendererId)formRendererID
fieldIdentifier:(NSString*)fieldIdentifier fieldIdentifier:(NSString*)fieldIdentifier
fieldUniqueID:(FieldRendererId)fieldRendererID
inFrame:(web::WebFrame*)frame inFrame:(web::WebFrame*)frame
completionHandler: completionHandler:
(void (^)(NSString*))completionHandler { (void (^)(NSString*))completionHandler {
DCHECK(completionHandler); DCHECK(completionHandler);
bool useRendererIDs = base::FeatureList::IsEnabled(
autofill::features::kAutofillUseUniqueRendererIDsOnIOS);
int formNumericID =
formRendererID ? formRendererID.value() : autofill::kNotSetRendererID;
int fieldNumericID =
fieldRendererID ? fieldRendererID.value() : autofill::kNotSetRendererID;
std::vector<base::Value> parameters; std::vector<base::Value> parameters;
parameters.push_back(base::Value(base::SysNSStringToUTF8(formName))); parameters.push_back(base::Value(base::SysNSStringToUTF8(formName)));
parameters.push_back(base::Value(formNumericID));
parameters.push_back(base::Value(base::SysNSStringToUTF8(fieldIdentifier))); parameters.push_back(base::Value(base::SysNSStringToUTF8(fieldIdentifier)));
parameters.push_back(base::Value(fieldNumericID));
parameters.push_back(base::Value(useRendererIDs));
autofill::ExecuteJavaScriptFunction( autofill::ExecuteJavaScriptFunction(
"autofill.clearAutofilledFields", parameters, frame, "autofill.clearAutofilledFields", parameters, frame,
autofill::CreateStringCallback(completionHandler)); autofill::CreateStringCallback(completionHandler));
......
...@@ -329,9 +329,13 @@ __gCrWeb.autofill['fillForm'] = function( ...@@ -329,9 +329,13 @@ __gCrWeb.autofill['fillForm'] = function(
* @return {string} JSON encoded list of renderer IDs of cleared elements. * @return {string} JSON encoded list of renderer IDs of cleared elements.
*/ */
__gCrWeb.autofill['clearAutofilledFields'] = function( __gCrWeb.autofill['clearAutofilledFields'] = function(
formName, fieldIdentifier) { formName, formUniqueID, fieldIdentifier, fieldUniqueID, useRendererIDs) {
const clearedElements = []; const clearedElements = [];
const form = __gCrWeb.form.getFormElementFromIdentifier(formName);
const form = useRendererIDs ?
__gCrWeb.form.getFormElementFromUniqueFormId(formUniqueID) :
__gCrWeb.form.getFormElementFromIdentifier(formName);
const controlElements = form ? const controlElements = form ?
__gCrWeb.form.getFormControlElements(form) : __gCrWeb.form.getFormControlElements(form) :
__gCrWeb.fill.getUnownedAutofillableFormFieldElements( __gCrWeb.fill.getUnownedAutofillableFormFieldElements(
...@@ -340,8 +344,12 @@ __gCrWeb.autofill['clearAutofilledFields'] = function( ...@@ -340,8 +344,12 @@ __gCrWeb.autofill['clearAutofilledFields'] = function(
let formField = null; let formField = null;
for (let i = 0; i < controlElements.length; ++i) { for (let i = 0; i < controlElements.length; ++i) {
if (__gCrWeb.form.getFieldIdentifier(controlElements[i]) == if ((useRendererIDs &&
fieldIdentifier) { __gCrWeb.fill.getUniqueID(controlElements[i]) ==
fieldUniqueID.toString()) ||
(!useRendererIDs &&
__gCrWeb.form.getFieldIdentifier(controlElements[i]) ==
fieldIdentifier)) {
formField = controlElements[i]; formField = controlElements[i];
break; break;
} }
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#endif #endif
using autofill::FieldRendererId; using autofill::FieldRendererId;
using autofill::FormRendererId;
using base::SysNSStringToUTF8; using base::SysNSStringToUTF8;
namespace { namespace {
...@@ -612,57 +613,74 @@ TEST_F(JsAutofillManagerTest, FillFormUsingRendererIDs) { ...@@ -612,57 +613,74 @@ TEST_F(JsAutofillManagerTest, FillFormUsingRendererIDs) {
EXPECT_NSEQ(@"{\"1\":\"Cool User\",\"2\":\"coolemail@com\"}", filling_result); EXPECT_NSEQ(@"{\"1\":\"Cool User\",\"2\":\"coolemail@com\"}", filling_result);
} }
// Tests form clearing (clearAutofilledFieldsForFormName::fillIdentifier: // Tests form clearing (clearAutofilledFieldsForFormName:formUniqueID:
// inFrame:completionHandler:) method. // fieldIdentifier:fieldUniqueID:inFrame:completionHandler:) method.
// method.
TEST_F(JsAutofillManagerTest, ClearForm) { TEST_F(JsAutofillManagerTest, ClearForm) {
LoadHtml(@"<html><body><form name='testform' method='post'>" for (bool use_renderer_ids : {true, false}) {
"<input type='text' id='firstname' name='firstname'/>" SCOPED_TRACE(testing::Message()
"<input type='email' id='email' name='email'/>" << "For use_renderer_ids=" << use_renderer_ids);
"</form></body></html>"); base::test::ScopedFeatureList scoped_feature_list;
RunFormsSearch(); std::vector<base::Feature> enabled_features;
std::vector<base::Feature> disabled_features;
std::vector<std::pair<NSString*, int>> field_ids = {{@"firstname", 1}, if (use_renderer_ids) {
{@"email", 2}}; enabled_features.push_back(
// Fill form fields. autofill::features::kAutofillUseUniqueRendererIDsOnIOS);
for (auto& field_data : field_ids) { } else {
NSString* getFieldScript = disabled_features.push_back(
[NSString stringWithFormat:@"document.getElementsByName('%@')[0]", autofill::features::kAutofillUseUniqueRendererIDsOnIOS);
field_data.first]; }
NSString* focusScript = scoped_feature_list.InitWithFeatures(enabled_features, disabled_features);
[NSString stringWithFormat:@"%@.focus()", getFieldScript];
ExecuteJavaScript(focusScript); LoadHtml(@"<html><body><form name='testform' method='post'>"
auto data = std::make_unique<base::DictionaryValue>(); "<input type='text' id='firstname' name='firstname'/>"
data->SetString("name", SysNSStringToUTF8(field_data.first)); "<input type='email' id='email' name='email'/>"
data->SetString("identifier", SysNSStringToUTF8(field_data.first)); "</form></body></html>");
data->SetInteger("unique_renderer_id", field_data.second); RunFormsSearch();
data->SetString("value", "testvalue");
__block BOOL success = NO; std::vector<std::pair<NSString*, int>> field_ids = {{@"firstname", 1},
[manager_ fillActiveFormField:std::move(data) {@"email", 2}};
inFrame:main_web_frame() // Fill form fields.
completionHandler:^(BOOL result) { for (auto& field_data : field_ids) {
success = result; NSString* getFieldScript =
}]; [NSString stringWithFormat:@"document.getElementsByName('%@')[0]",
field_data.first];
NSString* focusScript =
[NSString stringWithFormat:@"%@.focus()", getFieldScript];
ExecuteJavaScript(focusScript);
auto data = std::make_unique<base::DictionaryValue>();
data->SetString("name", SysNSStringToUTF8(field_data.first));
data->SetString("identifier", SysNSStringToUTF8(field_data.first));
data->SetInteger("unique_renderer_id", field_data.second);
data->SetString("value", "testvalue");
__block BOOL success = NO;
[manager_ fillActiveFormField:std::move(data)
inFrame:main_web_frame()
completionHandler:^(BOOL result) {
success = result;
}];
EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForActionTimeout, ^bool() {
return success;
}));
}
__block NSString* clearing_result = nil;
__block BOOL block_was_called = NO;
[manager_ clearAutofilledFieldsForFormName:@"testform"
formUniqueID:FormRendererId(0)
fieldIdentifier:@"firstname"
fieldUniqueID:FieldRendererId(1)
inFrame:main_web_frame()
completionHandler:^(NSString* result) {
clearing_result = [result copy];
block_was_called = YES;
}];
EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout( EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForActionTimeout, ^bool() { base::test::ios::kWaitForActionTimeout, ^bool() {
return success; return block_was_called;
})); }));
EXPECT_NSEQ(@"[\"1\",\"2\"]", clearing_result);
} }
__block NSString* clearing_result = nil;
__block BOOL block_was_called = NO;
[manager_ clearAutofilledFieldsForFormName:@"testform"
fieldIdentifier:@"firstname"
inFrame:main_web_frame()
completionHandler:^(NSString* result) {
clearing_result = [result copy];
block_was_called = YES;
}];
EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForActionTimeout, ^bool() {
return block_was_called;
}));
EXPECT_NSEQ(@"[\"1\",\"2\"]", clearing_result);
} }
} // namespace } // namespace
...@@ -181,14 +181,17 @@ using autofill::FieldRendererId; ...@@ -181,14 +181,17 @@ using autofill::FieldRendererId;
completionHandler:(nullable void (^)(void))completionHandler { completionHandler:(nullable void (^)(void))completionHandler {
web::WebFrame* frame = web::WebFrame* frame =
web::GetWebFrameWithId(_webState, base::SysNSStringToUTF8(frameID)); web::GetWebFrameWithId(_webState, base::SysNSStringToUTF8(frameID));
[_JSAutofillManager clearAutofilledFieldsForFormName:formName [_JSAutofillManager
fieldIdentifier:fieldIdentifier clearAutofilledFieldsForFormName:formName
inFrame:frame formUniqueID:_lastFormActivityUniqueFormID
completionHandler:^(NSString*) { fieldIdentifier:fieldIdentifier
if (completionHandler) { fieldUniqueID:_lastFormActivityUniqueFieldID
completionHandler(); inFrame:frame
} completionHandler:^(NSString*) {
}]; if (completionHandler) {
completionHandler();
}
}];
} }
- (void)fetchSuggestionsForFormWithName:(NSString*)formName - (void)fetchSuggestionsForFormWithName:(NSString*)formName
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment