diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-12 14:27:29 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-13 09:35:20 +0000 |
commit | c30a6232df03e1efbd9f3b226777b07e087a1122 (patch) | |
tree | e992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/components/autofill/ios | |
parent | 7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff) | |
download | qtwebengine-chromium-85-based.tar.gz |
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/components/autofill/ios')
12 files changed, 179 insertions, 120 deletions
diff --git a/chromium/components/autofill/ios/browser/autofill_agent.mm b/chromium/components/autofill/ios/browser/autofill_agent.mm index fceb06e2fda..fafe880b37e 100644 --- a/chromium/components/autofill/ios/browser/autofill_agent.mm +++ b/chromium/components/autofill/ios/browser/autofill_agent.mm @@ -187,8 +187,7 @@ void GetFormField(autofill::FormFieldData* field, _prefObserverBridge->ObserveChangesForPreference( autofill::prefs::kAutofillProfileEnabled, &_prefChangeRegistrar); - _jsAutofillManager = [[JsAutofillManager alloc] - initWithReceiver:_webState->GetJSInjectionReceiver()]; + _jsAutofillManager = [[JsAutofillManager alloc] init]; } return self; } diff --git a/chromium/components/autofill/ios/browser/autofill_util.h b/chromium/components/autofill/ios/browser/autofill_util.h index 7065abd8203..8c4f61538ee 100644 --- a/chromium/components/autofill/ios/browser/autofill_util.h +++ b/chromium/components/autofill/ios/browser/autofill_util.h @@ -72,7 +72,6 @@ bool ExtractFormFieldData(const base::DictionaryValue& field, void ExecuteJavaScriptFunction(const std::string& name, const std::vector<base::Value>& parameters, web::WebFrame* frame, - CRWJSInjectionReceiver* js_injection_receiver, base::OnceCallback<void(NSString*)> callback); } // namespace autofill diff --git a/chromium/components/autofill/ios/browser/autofill_util.mm b/chromium/components/autofill/ios/browser/autofill_util.mm index 8e14a554ba2..af140f29505 100644 --- a/chromium/components/autofill/ios/browser/autofill_util.mm +++ b/chromium/components/autofill/ios/browser/autofill_util.mm @@ -19,7 +19,6 @@ #include "components/autofill/core/common/autofill_util.h" #include "components/autofill/core/common/form_data.h" #include "components/autofill/core/common/form_field_data.h" -#import "ios/web/public/deprecated/crw_js_injection_receiver.h" #import "ios/web/public/navigation/navigation_item.h" #import "ios/web/public/navigation/navigation_manager.h" #include "ios/web/public/security/ssl_status.h" @@ -27,6 +26,9 @@ #include "url/gurl.h" #include "url/origin.h" +using base::NumberToString; +using base::StringToUint; + namespace { // The timeout for any JavaScript call in this file. const int64_t kJavaScriptExecutionTimeoutInSeconds = 5; @@ -50,17 +52,11 @@ bool IsContextSecureForWebState(web::WebState* web_state) { } std::unique_ptr<base::Value> ParseJson(NSString* json_string) { - // Convert JSON string to JSON object |JSONValue|. - int error_code = 0; - std::string error_message; - std::unique_ptr<base::Value> json_value( - base::JSONReader::ReadAndReturnErrorDeprecated( - base::SysNSStringToUTF8(json_string), base::JSON_PARSE_RFC, - &error_code, &error_message)); - if (error_code) + base::Optional<base::Value> json_value = + base::JSONReader::Read(base::SysNSStringToUTF8(json_string)); + if (!json_value) return nullptr; - - return json_value; + return base::Value::ToUniquePtrValue(std::move(*json_value)); } bool ExtractFormsData(NSString* forms_json, @@ -123,9 +119,9 @@ bool ExtractFormData(const base::Value& form_value, std::string unique_renderer_id; form_dictionary->GetString("unique_renderer_id", &unique_renderer_id); - if (!unique_renderer_id.empty()) { - base::StringToUint(unique_renderer_id, - &form_data->unique_renderer_id.value()); + if (!unique_renderer_id.empty() && + unique_renderer_id != NumberToString(kNotSetRendererID)) { + StringToUint(unique_renderer_id, &form_data->unique_renderer_id.value()); } else { form_data->unique_renderer_id = FormRendererId(); } @@ -141,6 +137,7 @@ bool ExtractFormData(const base::Value& form_value, form_dictionary->GetBoolean("is_form_tag", &form_data->is_form_tag); form_dictionary->GetBoolean("is_formless_checkout", &form_data->is_formless_checkout); + form_dictionary->GetString("frame_id", &form_data->frame_id); // Field list (mandatory) is extracted. const base::ListValue* fields_list = nullptr; @@ -169,9 +166,9 @@ bool ExtractFormFieldData(const base::DictionaryValue& field, std::string unique_renderer_id; field.GetString("unique_renderer_id", &unique_renderer_id); - if (!unique_renderer_id.empty()) { - base::StringToUint(unique_renderer_id, - &field_data->unique_renderer_id.value()); + if (!unique_renderer_id.empty() && + unique_renderer_id != NumberToString(kNotSetRendererID)) { + StringToUint(unique_renderer_id, &field_data->unique_renderer_id.value()); } else { field_data->unique_renderer_id = FieldRendererId(); } @@ -233,7 +230,6 @@ bool ExtractFormFieldData(const base::DictionaryValue& field, void ExecuteJavaScriptFunction(const std::string& name, const std::vector<base::Value>& parameters, web::WebFrame* frame, - CRWJSInjectionReceiver* js_injection_receiver, base::OnceCallback<void(NSString*)> callback) { __block base::OnceCallback<void(NSString*)> cb = std::move(callback); diff --git a/chromium/components/autofill/ios/browser/js_autofill_manager.h b/chromium/components/autofill/ios/browser/js_autofill_manager.h index 15c404b9b3a..7ebd532dcd1 100644 --- a/chromium/components/autofill/ios/browser/js_autofill_manager.h +++ b/chromium/components/autofill/ios/browser/js_autofill_manager.h @@ -8,7 +8,6 @@ #include "base/ios/block_types.h" #include "base/values.h" #include "components/autofill/core/common/autofill_constants.h" -#import "ios/web/public/deprecated/crw_js_injection_receiver.h" namespace web { class WebFrame; @@ -72,12 +71,6 @@ class WebFrame; - (void)toggleTrackingUserEditedFields:(BOOL)state inFrame:(web::WebFrame*)frame; -// Designated initializer. |receiver| should not be nil. -- (instancetype)initWithReceiver:(CRWJSInjectionReceiver*)receiver - NS_DESIGNATED_INITIALIZER; - -- (instancetype)init NS_UNAVAILABLE; - @end #endif // COMPONENTS_AUTOFILL_IOS_BROWSER_JS_AUTOFILL_MANAGER_H_ diff --git a/chromium/components/autofill/ios/browser/js_autofill_manager.mm b/chromium/components/autofill/ios/browser/js_autofill_manager.mm index 13592c9ba3a..4e8f9645df4 100644 --- a/chromium/components/autofill/ios/browser/js_autofill_manager.mm +++ b/chromium/components/autofill/ios/browser/js_autofill_manager.mm @@ -12,8 +12,6 @@ #include "base/command_line.h" #include "base/feature_list.h" #include "base/format_macros.h" -#include "base/json/json_writer.h" -#include "base/json/string_escape.h" #include "base/mac/foundation_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/sys_string_conversions.h" @@ -26,19 +24,7 @@ #error "This file requires ARC support." #endif -@implementation JsAutofillManager { - // The injection receiver used to evaluate JavaScript. - __weak CRWJSInjectionReceiver* _receiver; -} - -- (instancetype)initWithReceiver:(CRWJSInjectionReceiver*)receiver { - DCHECK(receiver); - self = [super init]; - if (self) { - _receiver = receiver; - } - return self; -} +@implementation JsAutofillManager - (void)addJSDelayInFrame:(web::WebFrame*)frame { const base::CommandLine* command_line = @@ -52,7 +38,7 @@ std::vector<base::Value> parameters; parameters.push_back(base::Value(commandLineDelay)); autofill::ExecuteJavaScriptFunction( - "autofill.setDelay", parameters, frame, _receiver, + "autofill.setDelay", parameters, frame, base::OnceCallback<void(NSString*)>()); } } @@ -70,8 +56,7 @@ parameters.push_back(base::Value(static_cast<int>(requiredFieldsCount))); parameters.push_back(base::Value(restrictUnownedFieldsToFormlessCheckout)); autofill::ExecuteJavaScriptFunction("autofill.extractForms", parameters, - frame, _receiver, - base::BindOnce(completionHandler)); + frame, base::BindOnce(completionHandler)); } #pragma mark - @@ -84,7 +69,7 @@ std::vector<base::Value> parameters; parameters.push_back(std::move(*data)); autofill::ExecuteJavaScriptFunction("autofill.fillActiveFormField", - parameters, frame, _receiver, + parameters, frame, base::BindOnce(^(NSString*) { completionHandler(); })); @@ -94,7 +79,7 @@ std::vector<base::Value> parameters; parameters.push_back(base::Value(state ? 200 : 0)); autofill::ExecuteJavaScriptFunction("formHandlers.trackFormMutations", - parameters, frame, _receiver, + parameters, frame, base::OnceCallback<void(NSString*)>()); } @@ -104,7 +89,7 @@ parameters.push_back(base::Value(static_cast<bool>(state))); autofill::ExecuteJavaScriptFunction( "formHandlers.toggleTrackingUserEditedFields", parameters, frame, - _receiver, base::OnceCallback<void(NSString*)>()); + base::OnceCallback<void(NSString*)>()); } - (void)fillForm:(std::unique_ptr<base::Value>)data @@ -121,7 +106,7 @@ parameters.push_back(std::move(*data)); parameters.push_back(base::Value(fieldIdentifier)); autofill::ExecuteJavaScriptFunction("autofill.fillForm", parameters, frame, - _receiver, base::BindOnce(^(NSString*) { + base::BindOnce(^(NSString*) { completionHandler(); })); } @@ -135,7 +120,7 @@ parameters.push_back(base::Value(base::SysNSStringToUTF8(formName))); parameters.push_back(base::Value(base::SysNSStringToUTF8(fieldIdentifier))); autofill::ExecuteJavaScriptFunction("autofill.clearAutofilledFields", - parameters, frame, _receiver, + parameters, frame, base::BindOnce(^(NSString*) { completionHandler(); })); @@ -147,7 +132,7 @@ std::vector<base::Value> parameters; parameters.push_back(std::move(*data)); autofill::ExecuteJavaScriptFunction("autofill.fillPredictionData", parameters, - frame, _receiver, + frame, base::OnceCallback<void(NSString*)>()); } diff --git a/chromium/components/autofill/ios/browser/js_suggestion_manager.mm b/chromium/components/autofill/ios/browser/js_suggestion_manager.mm index e5767bba023..837546f40de 100644 --- a/chromium/components/autofill/ios/browser/js_suggestion_manager.mm +++ b/chromium/components/autofill/ios/browser/js_suggestion_manager.mm @@ -56,8 +56,7 @@ parameters.push_back(base::Value(base::SysNSStringToUTF8(fieldName))); autofill::ExecuteJavaScriptFunction( "suggestion.selectNextElement", parameters, - [self frameWithFrameID:frameID], _receiver, - base::OnceCallback<void(NSString*)>()); + [self frameWithFrameID:frameID], base::OnceCallback<void(NSString*)>()); } - (void)selectPreviousElementInFrameWithID:(NSString*)frameID { @@ -72,8 +71,7 @@ parameters.push_back(base::Value(base::SysNSStringToUTF8(fieldName))); autofill::ExecuteJavaScriptFunction( "suggestion.selectPreviousElement", parameters, - [self frameWithFrameID:frameID], _receiver, - base::OnceCallback<void(NSString*)>()); + [self frameWithFrameID:frameID], base::OnceCallback<void(NSString*)>()); } - (void)fetchPreviousAndNextElementsPresenceInFrameWithID:(NSString*)frameID @@ -98,8 +96,7 @@ parameters.push_back(base::Value(base::SysNSStringToUTF8(fieldName))); autofill::ExecuteJavaScriptFunction( "suggestion.hasPreviousNextElements", parameters, - [self frameWithFrameID:frameID], _receiver, - base::BindOnce(^(NSString* result) { + [self frameWithFrameID:frameID], base::BindOnce(^(NSString* result) { // The result maybe an empty string here due to 2 reasons: // 1) When there is an exception running the JS // 2) There is a race when the page is changing due to which @@ -127,8 +124,7 @@ std::vector<base::Value> parameters; autofill::ExecuteJavaScriptFunction( "suggestion.blurActiveElement", parameters, - [self frameWithFrameID:frameID], _receiver, - base::OnceCallback<void(NSString*)>()); + [self frameWithFrameID:frameID], base::OnceCallback<void(NSString*)>()); } - (web::WebFrame*)frameWithFrameID:(NSString*)frameID { diff --git a/chromium/components/autofill/ios/form_util/form_activity_tab_helper.mm b/chromium/components/autofill/ios/form_util/form_activity_tab_helper.mm index e04639c4d0c..d4e4020a628 100644 --- a/chromium/components/autofill/ios/form_util/form_activity_tab_helper.mm +++ b/chromium/components/autofill/ios/form_util/form_activity_tab_helper.mm @@ -7,6 +7,7 @@ #import <Foundation/Foundation.h> #include "base/bind.h" +#include "base/logging.h" #include "base/strings/string_number_conversions.h" #include "base/values.h" #include "components/autofill/ios/form_util/form_activity_observer.h" diff --git a/chromium/components/autofill/ios/form_util/form_activity_tab_helper_unittest.mm b/chromium/components/autofill/ios/form_util/form_activity_tab_helper_unittest.mm index cffa22b4fa1..9acd740d56f 100644 --- a/chromium/components/autofill/ios/form_util/form_activity_tab_helper_unittest.mm +++ b/chromium/components/autofill/ios/form_util/form_activity_tab_helper_unittest.mm @@ -16,6 +16,8 @@ #import "ios/web/public/test/web_test_with_web_state.h" #include "testing/platform_test.h" +using web::WebFrame; + class FormTestClient : public web::TestWebClient { public: NSString* GetDocumentStartScriptForAllFrames( @@ -61,19 +63,22 @@ TEST_F(FormActivityTabHelperTest, TestObserverDocumentSubmitted) { ExecuteJavaScript(@"__gCrWeb.fill.setUpForUniqueIDs(0);"); ASSERT_FALSE(observer_->submit_document_info()); const std::string kTestFormName("form-name"); - const std::string kTestFormData( - "[{\"name\":\"form-name\",\"origin\":\"https://chromium.test/" - "\",\"action\":\"https://chromium.test/\"," - "\"name_attribute\":\"form-name\",\"id_attribute\":\"\"," - "\"unique_renderer_id\":\"0\"}]"); + + WebFrame* main_frame = web_state()->GetWebFramesManager()->GetMainWebFrame(); + std::string mainFrameID = main_frame->GetFrameId(); + const std::string kTestFormData = + std::string("[{\"name\":\"form-name\",\"origin\":\"https://chromium.test/" + "\",\"action\":\"https://chromium.test/\"," + "\"name_attribute\":\"form-name\",\"id_attribute\":\"\"," + "\"unique_renderer_id\":\"0\",\"frame_id\":\"") + + mainFrameID + std::string("\"}]"); + bool has_user_gesture = false; bool form_in_main_frame = true; EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout( base::test::ios::kWaitForJSCompletionTimeout, ^bool { return web_state()->GetWebFramesManager()->GetMainWebFrame() != nullptr; })); - web::WebFrame* main_frame = - web_state()->GetWebFramesManager()->GetMainWebFrame(); ExecuteJavaScript(@"document.getElementById('submit').click();"); ASSERT_TRUE(observer_->submit_document_info()); @@ -96,19 +101,22 @@ TEST_F(FormActivityTabHelperTest, TestFormSubmittedHook) { ExecuteJavaScript(@"__gCrWeb.fill.setUpForUniqueIDs(0);"); ASSERT_FALSE(observer_->submit_document_info()); const std::string kTestFormName("form-name"); - const std::string kTestFormData( - "[{\"name\":\"form-name\",\"origin\":\"https://chromium.test/" - "\",\"action\":\"https://chromium.test/\"," - "\"name_attribute\":\"form-name\",\"id_attribute\":\"form\"," - "\"unique_renderer_id\":\"0\"}]"); + + WebFrame* main_frame = web_state()->GetWebFramesManager()->GetMainWebFrame(); + std::string mainFrameID = main_frame->GetFrameId(); + const std::string kTestFormData = + std::string("[{\"name\":\"form-name\",\"origin\":\"https://chromium.test/" + "\",\"action\":\"https://chromium.test/\"," + "\"name_attribute\":\"form-name\",\"id_attribute\":\"form\"," + "\"unique_renderer_id\":\"0\",\"frame_id\":\"") + + mainFrameID + std::string("\"}]"); + bool has_user_gesture = false; bool form_in_main_frame = true; EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout( base::test::ios::kWaitForJSCompletionTimeout, ^bool { return web_state()->GetWebFramesManager()->GetMainWebFrame() != nullptr; })); - web::WebFrame* main_frame = - web_state()->GetWebFramesManager()->GetMainWebFrame(); ExecuteJavaScript(@"document.getElementById('form').submit();"); ASSERT_TRUE(observer_->submit_document_info()); @@ -133,8 +141,7 @@ TEST_F(FormActivityTabHelperTest, TestObserverFormActivityFrameMessaging) { base::test::ios::kWaitForJSCompletionTimeout, ^bool { return web_state()->GetWebFramesManager()->GetMainWebFrame() != nullptr; })); - web::WebFrame* main_frame = - web_state()->GetWebFramesManager()->GetMainWebFrame(); + WebFrame* main_frame = web_state()->GetWebFramesManager()->GetMainWebFrame(); ASSERT_FALSE(observer_->form_activity_info()); // First call will set document.activeElement (which is usually set by user // action. Second call will trigger the message. diff --git a/chromium/components/autofill/ios/form_util/form_unittest.mm b/chromium/components/autofill/ios/form_util/form_unittest.mm index b5e60552017..3f505ad8cd7 100644 --- a/chromium/components/autofill/ios/form_util/form_unittest.mm +++ b/chromium/components/autofill/ios/form_util/form_unittest.mm @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#import "base/test/ios/wait_util.h" #include "components/autofill/ios/form_util/form_activity_tab_helper.h" #include "components/autofill/ios/form_util/test_form_activity_observer.h" #import "ios/web/public/browser_state.h" @@ -16,6 +17,9 @@ #error "This file requires ARC support." #endif +using base::test::ios::WaitUntilConditionOrTimeout; +using base::test::ios::kWaitForJSCompletionTimeout; + class FormTestClient : public web::TestWebClient { public: NSString* GetDocumentStartScriptForAllFrames( @@ -60,9 +64,9 @@ TEST_F(FormJsTest, KeyUpEventFocused) { "var ev = new KeyboardEvent('keyup', {bubbles:true});" "e.dispatchEvent(ev);"); autofill::TestFormActivityObserver* block_observer = observer_.get(); - WaitForCondition(^bool { + ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{ return block_observer->form_activity_info() != nullptr; - }); + })); autofill::TestFormActivityInfo* info = observer_->form_activity_info(); ASSERT_TRUE(info); EXPECT_EQ("keyup", info->form_activity.type); @@ -93,9 +97,9 @@ TEST_F(FormJsTest, FocusMainFrame) { ASSERT_FALSE(observer_->form_activity_info()); ExecuteJavaScript(@"document.getElementById('id1').focus();"); autofill::TestFormActivityObserver* block_observer = observer_.get(); - WaitForCondition(^bool { + ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{ return block_observer->form_activity_info() != nullptr; - }); + })); autofill::TestFormActivityInfo* info = observer_->form_activity_info(); ASSERT_TRUE(info); EXPECT_EQ("focus", info->form_activity.type); @@ -131,9 +135,9 @@ TEST_F(FormJsTest, FocusSameOriginIFrame) { @"document.getElementById('frame1').contentDocument.getElementById('id1')" @".focus()"); autofill::TestFormActivityObserver* block_observer = observer_.get(); - WaitForCondition(^bool { + ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{ return block_observer->form_activity_info() != nullptr; - }); + })); autofill::TestFormActivityInfo* info = observer_->form_activity_info(); ASSERT_TRUE(info); EXPECT_EQ("focus", info->form_activity.type); @@ -168,10 +172,10 @@ TEST_F(FormJsTest, AddForm) { @"document.body.appendChild(form);"); autofill::TestFormActivityObserver* block_observer = observer_.get(); __block autofill::TestFormActivityInfo* info = nil; - WaitForCondition(^{ + ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{ info = block_observer->form_activity_info(); return info != nil; - }); + })); EXPECT_EQ("form_changed", info->form_activity.type); EXPECT_FALSE(info->form_activity.input_missing); } @@ -186,10 +190,10 @@ TEST_F(FormJsTest, AddInput) { @"document.getElementById('formId').appendChild(input);"); autofill::TestFormActivityObserver* block_observer = observer_.get(); __block autofill::TestFormActivityInfo* info = nil; - WaitForCondition(^{ + ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{ info = block_observer->form_activity_info(); return info != nil; - }); + })); EXPECT_EQ("form_changed", info->form_activity.type); EXPECT_FALSE(info->form_activity.input_missing); } @@ -204,10 +208,10 @@ TEST_F(FormJsTest, AddSelect) { @"document.getElementById('formId').appendChild(select);"); autofill::TestFormActivityObserver* block_observer = observer_.get(); __block autofill::TestFormActivityInfo* info = nil; - WaitForCondition(^{ + ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{ info = block_observer->form_activity_info(); return info != nil; - }); + })); EXPECT_EQ("form_changed", info->form_activity.type); EXPECT_FALSE(info->form_activity.input_missing); } @@ -225,10 +229,32 @@ TEST_F(FormJsTest, AddOption) { @"document.getElementById('select1').appendChild(option);"); autofill::TestFormActivityObserver* block_observer = observer_.get(); __block autofill::TestFormActivityInfo* info = nil; - WaitForCondition(^{ + ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{ info = block_observer->form_activity_info(); return info != nil; - }); + })); EXPECT_EQ("form_changed", info->form_activity.type); EXPECT_FALSE(info->form_activity.input_missing); } + +// Tests that removing password form triggers 'password_form_removed" event. +TEST_F(FormJsTest, RemoveForm) { + LoadHtml(@"<form id=\"form1\">" + "<input type=\"text\" name=\"username\" id=\"id1\">" + "<input type=\"password\" name=\"password\" id=\"id2\">" + "<input type=\"submit\" id=\"submit_input\"/>" + "</form>"); + ExecuteJavaScript(@"__gCrWeb.fill.setUpForUniqueIDs(0);" + @"__gCrWeb.formHandlers.trackFormMutations(10);" + @"var form1 = document.getElementById('form1');" + @"__gCrWeb.fill.setUniqueIDIfNeeded(form1);" + @"form1.parentNode.removeChild(form1);"); + autofill::TestFormActivityObserver* block_observer = observer_.get(); + __block autofill::TestFormActivityInfo* info = nil; + ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{ + info = block_observer->form_activity_info(); + return info != nil; + })); + EXPECT_EQ("password_form_removed", info->form_activity.type); + EXPECT_FALSE(info->form_activity.input_missing); +} diff --git a/chromium/components/autofill/ios/form_util/resources/fill.js b/chromium/components/autofill/ios/form_util/resources/fill.js index a48befb78a5..1108ece5273 100644 --- a/chromium/components/autofill/ios/form_util/resources/fill.js +++ b/chromium/components/autofill/ios/form_util/resources/fill.js @@ -34,6 +34,7 @@ let AutofillFormFieldData; * origin: string, * action: string, * fields: Array<AutofillFormFieldData> + * frame_id: string * }} */ let AutofillFormData; @@ -144,6 +145,16 @@ __gCrWeb.fill.ROLE_ATTRIBUTE_PRESENTATION = 0; __gCrWeb.fill.RENDERER_ID_NOT_SET = '-1'; /** + * The name of the JS Symbol used to set stable unique form and field IDs. + * + * This variable is |kNotSetRendererID| from + * chromium/src/components/autofill/ios/browser/autofill_util.h + * + * @const {string} + */ +__gCrWeb.fill.UNIQUE_ID_SYMBOL_NAME = '__gChrome~uniqueID'; + +/** * Returns true if an element can be autocompleted. * * This method aims to provide the same logic as method @@ -838,13 +849,10 @@ __gCrWeb.fill.webFormElementToFormData = function( form['name_attribute'] = formElement.getAttribute('name') || ''; form['id_attribute'] = formElement.getAttribute('id') || ''; - try { - __gCrWeb.fill.setUniqueIDIfNeeded(formElement); - const uniqueID = Symbol.for('__gChrome~uniqueID'); - form['unique_renderer_id'] = formElement[uniqueID].toString(); - } catch (e) { - form['unique_renderer_id'] = __gCrWeb.fill.RENDERER_ID_NOT_SET; - } + __gCrWeb.fill.setUniqueIDIfNeeded(formElement); + form['unique_renderer_id'] = __gCrWeb.fill.getUniqueID(formElement); + + form['frame_id'] = frame.__gCrWeb.message.getFrameId(); // Note different from form_autofill_util.cc version of this method, which // computes |form.action| using document.completeURL(form_element.action()) @@ -1938,12 +1946,8 @@ __gCrWeb.fill.webFormControlElementToFormField = function( field['name_attribute'] = element.getAttribute('name') || ''; field['id_attribute'] = element.getAttribute('id') || ''; - try { - const uniqueID = Symbol.for('__gChrome~uniqueID'); - field['unique_renderer_id'] = element[uniqueID].toString(); - } catch (e) { - field['unique_renderer_id'] = __gCrWeb.fill.RENDERER_ID_NOT_SET; - } + __gCrWeb.fill.setUniqueIDIfNeeded(element); + field['unique_renderer_id'] = __gCrWeb.fill.getUniqueID(element); field['form_control_type'] = element.type; const autocompleteAttribute = element.getAttribute('autocomplete'); @@ -2298,7 +2302,7 @@ __gCrWeb.fill.extractAutofillableElementsFromSet = function(controlElements) { * @param {int} nextAvailableID Next available integer. */ __gCrWeb.fill['setUpForUniqueIDs'] = function(nextAvailableID) { - const uniqueID = Symbol.for('__gChrome~uniqueID'); + const uniqueID = Symbol.for(__gCrWeb.fill.UNIQUE_ID_SYMBOL_NAME); document[uniqueID] = nextAvailableID; }; @@ -2306,9 +2310,29 @@ __gCrWeb.fill['setUpForUniqueIDs'] = function(nextAvailableID) { * @param {Element} element Form or form input element. */ __gCrWeb.fill.setUniqueIDIfNeeded = function(element) { - const uniqueID = Symbol.for('__gChrome~uniqueID'); - if (typeof element[uniqueID] === 'undefined') { - element[uniqueID] = document[uniqueID]++; + try { + const uniqueID = Symbol.for(__gCrWeb.fill.UNIQUE_ID_SYMBOL_NAME); + if (typeof element[uniqueID] === 'undefined') { + element[uniqueID] = document[uniqueID]++; + } + } catch (e) { + } +}; + +/** + * @param {Element} element Form or form input element. + * @return {String} Unique stable ID converted to string.. + */ +__gCrWeb.fill.getUniqueID = function(element) { + try { + const uniqueID = Symbol.for(__gCrWeb.fill.UNIQUE_ID_SYMBOL_NAME); + if (typeof element[uniqueID] !== 'undefined' && !isNaN(element[uniqueID])) { + return element[uniqueID].toString(); + } else { + return __gCrWeb.fill.RENDERER_ID_NOT_SET; + } + } catch (e) { + return __gCrWeb.fill.RENDERER_ID_NOT_SET; } }; diff --git a/chromium/components/autofill/ios/form_util/resources/form.js b/chromium/components/autofill/ios/form_util/resources/form.js index d393d81f905..e857c9e88b5 100644 --- a/chromium/components/autofill/ios/form_util/resources/form.js +++ b/chromium/components/autofill/ios/form_util/resources/form.js @@ -280,7 +280,7 @@ __gCrWeb.form.getFormElementFromUniqueFormId = function(identifier) { const forms = document.forms; for (let i = 0; i < forms.length; i++) { const form = forms[i]; - const uniqueID = Symbol.for('__gChrome~uniqueID'); + const uniqueID = Symbol.for(__gCrWeb.fill.UNIQUE_ID_SYMBOL_NAME); if (identifier === form[uniqueID]) { return form; } diff --git a/chromium/components/autofill/ios/form_util/resources/form_handlers.js b/chromium/components/autofill/ios/form_util/resources/form_handlers.js index a0e2bad0577..69f0d8d2c9c 100644 --- a/chromium/components/autofill/ios/form_util/resources/form_handlers.js +++ b/chromium/components/autofill/ios/form_util/resources/form_handlers.js @@ -110,22 +110,16 @@ function formActivity_(evt) { if (target !== lastFocusedElement) { return; } - let formUniqueIdString = __gCrWeb.fill.RENDERER_ID_NOT_SET; - let fieldUniqueIdString = __gCrWeb.fill.RENDERER_ID_NOT_SET; - try { - __gCrWeb.fill.setUniqueIDIfNeeded(target.form); - __gCrWeb.fill.setUniqueIDIfNeeded(target); - const uniqueID = Symbol.for('__gChrome~uniqueID'); - formUniqueIdString = target.form[uniqueID].toString(); - fieldUniqueIdString = target[uniqueID].toString(); - } catch (e) { - } + __gCrWeb.fill.setUniqueIDIfNeeded(target.form); + __gCrWeb.fill.setUniqueIDIfNeeded(target); + const formUniqueId = __gCrWeb.fill.getUniqueID(target.form); + const fieldUniqueId = __gCrWeb.fill.getUniqueID(target); const msg = { 'command': 'form.activity', 'formName': __gCrWeb.form.getFormIdentifier(target.form), - 'uniqueFormID': formUniqueIdString, + 'uniqueFormID': formUniqueId, 'fieldIdentifier': __gCrWeb.form.getFieldIdentifier(target), - 'uniqueFieldID': fieldUniqueIdString, + 'uniqueFieldID': fieldUniqueId, 'fieldType': fieldType, 'type': evt.type, 'value': value, @@ -267,6 +261,45 @@ __gCrWeb.formHandlers['trackFormMutations'] = function(delay) { }; return sendFormMutationMessageAfterDelay_(msg, delay); } + + const removedElements = []; + for (let j = 0; j < mutation.removedNodes.length; j++) { + const node = mutation.removedNodes[j]; + // Ignore non-element nodes. + if (node.nodeType !== Node.ELEMENT_NODE) { + continue; + } + removedElements.push(node); + [].push.apply( + removedElements, [].slice.call(node.getElementsByTagName('FORM'))); + } + const formGone = removedElements.find(function(element) { + if (element.tagName.match(/(FORM)/)) { + for (let k = 0; k < element.elements.length; k++) { + if (element.elements[k].tagName.match(/(INPUT)/) && + element.elements[k].type === 'password') { + return true; + } + } + return false; + } + return false; + }); + const uniqueFormId = __gCrWeb.fill.getUniqueID(formGone); + if (formGone) { + const msg = { + 'command': 'form.activity', + 'formName': '', + 'uniqueFormID': uniqueFormId, + 'fieldIdentifier': '', + 'uniqueFieldID': '', + 'fieldType': '', + 'type': 'password_form_removed', + 'value': '', + 'hasUserGesture': false + }; + return sendFormMutationMessageAfterDelay_(msg, delay); + } } }); formMutationObserver.observe(document, {childList: true, subtree: true}); |