summaryrefslogtreecommitdiff
path: root/chromium/components/autofill/ios
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-12 14:27:29 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-13 09:35:20 +0000
commitc30a6232df03e1efbd9f3b226777b07e087a1122 (patch)
treee992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/components/autofill/ios
parent7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff)
downloadqtwebengine-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')
-rw-r--r--chromium/components/autofill/ios/browser/autofill_agent.mm3
-rw-r--r--chromium/components/autofill/ios/browser/autofill_util.h1
-rw-r--r--chromium/components/autofill/ios/browser/autofill_util.mm32
-rw-r--r--chromium/components/autofill/ios/browser/js_autofill_manager.h7
-rw-r--r--chromium/components/autofill/ios/browser/js_autofill_manager.mm33
-rw-r--r--chromium/components/autofill/ios/browser/js_suggestion_manager.mm12
-rw-r--r--chromium/components/autofill/ios/form_util/form_activity_tab_helper.mm1
-rw-r--r--chromium/components/autofill/ios/form_util/form_activity_tab_helper_unittest.mm39
-rw-r--r--chromium/components/autofill/ios/form_util/form_unittest.mm54
-rw-r--r--chromium/components/autofill/ios/form_util/resources/fill.js58
-rw-r--r--chromium/components/autofill/ios/form_util/resources/form.js2
-rw-r--r--chromium/components/autofill/ios/form_util/resources/form_handlers.js57
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});