diff options
author | gcasto@chromium.org <gcasto@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-01 20:29:59 +0000 |
---|---|---|
committer | gcasto@chromium.org <gcasto@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-01 20:29:59 +0000 |
commit | b9c2571754f15540116873367429a8f7bb560510 (patch) | |
tree | d73e6d706c00e1e86cc2c8ddea45fa39453c066b /chrome/renderer | |
parent | ea5c5f05ca982448272cbfc9d0384a542c84d3b8 (diff) | |
download | chromium_src-b9c2571754f15540116873367429a8f7bb560510.zip chromium_src-b9c2571754f15540116873367429a8f7bb560510.tar.gz chromium_src-b9c2571754f15540116873367429a8f7bb560510.tar.bz2 |
Use shadow DOM API to show icon for password generation.
The key icon in this CL is rough draft and will be improved before launch.
BUG=114092
TEST=Ran PasswordGenerationManagerTest
Review URL: https://chromiumcodereview.appspot.com/10449099
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@140091 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer')
3 files changed, 98 insertions, 48 deletions
diff --git a/chrome/renderer/autofill/password_generation_manager.cc b/chrome/renderer/autofill/password_generation_manager.cc index b4bc16f..6abe555 100644 --- a/chrome/renderer/autofill/password_generation_manager.cc +++ b/chrome/renderer/autofill/password_generation_manager.cc @@ -6,11 +6,14 @@ #include "base/logging.h" #include "chrome/common/autofill_messages.h" +#include "content/public/renderer/render_view.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputElement.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebFormElement.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebCString.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebVector.h" #include "ui/gfx/rect.h" @@ -20,7 +23,9 @@ namespace autofill { PasswordGenerationManager::PasswordGenerationManager( content::RenderView* render_view) : content::RenderViewObserver(render_view), - enabled_(false) {} + enabled_(false) { + render_view->GetWebView()->addTextFieldDecoratorClient(this); +} PasswordGenerationManager::~PasswordGenerationManager() {} void PasswordGenerationManager::DidFinishDocumentLoad(WebKit::WebFrame* frame) { @@ -29,14 +34,14 @@ void PasswordGenerationManager::DidFinishDocumentLoad(WebKit::WebFrame* frame) { if (!enabled_) return; - if (!ShouldAnalyzeFrame(*frame)) + if (!ShouldAnalyzeDocument(frame->document())) return; WebKit::WebVector<WebKit::WebFormElement> forms; frame->document().forms(forms); for (size_t i = 0; i < forms.size(); ++i) { const WebKit::WebFormElement& web_form = forms[i]; - if (!web_form.autoComplete()) + if (web_form.isNull() || !web_form.autoComplete()) continue; // Grab all of the passwords for each form. @@ -50,21 +55,26 @@ void PasswordGenerationManager::DidFinishDocumentLoad(WebKit::WebFrame* frame) { if (input_element && input_element->isPasswordField()) passwords.push_back(*input_element); } + // For now, just assume that if there are two password fields in the - // form that this is meant for account creation. + // form that this is meant for account creation. Also, we assume that there + // is only one account creation field per URL. // TODO(gcasto): Determine better heauristics for this. if (passwords.size() == 2) { - account_creation_elements_ = make_pair(passwords[0], passwords); - break; + passwords_ = passwords; + // Make the decoration visible for this element. + passwords[0].decorationElementFor(this).setAttribute("style", + "display:block"); + return; } } } -bool PasswordGenerationManager::ShouldAnalyzeFrame( - const WebKit::WebFrame& frame) const { +bool PasswordGenerationManager::ShouldAnalyzeDocument( + const WebKit::WebDocument& document) const { // Make sure that this security origin is allowed to use password manager. // Generating a password that can't be saved is a bad idea. - WebKit::WebSecurityOrigin origin = frame.document().securityOrigin(); + WebKit::WebSecurityOrigin origin = document.securityOrigin(); if (!origin.canAccessPasswordManager()) { DVLOG(1) << "No PasswordManager access"; return false; @@ -73,25 +83,44 @@ bool PasswordGenerationManager::ShouldAnalyzeFrame( return true; } -void PasswordGenerationManager::FocusedNodeChanged( - const WebKit::WebNode& node) { - WebKit::WebInputElement input_element = - node.toConst<WebKit::WebInputElement>(); - if (!input_element.isNull() && - account_creation_elements_.first == input_element) { - gfx::Rect rect(input_element.boundsInViewportSpace()); - webkit::forms::PasswordForm* password_form( - webkit::forms::PasswordFormDomManager::CreatePasswordForm( - input_element.form())); - - if (password_form) { - Send(new AutofillHostMsg_ShowPasswordGenerationPopup(routing_id(), - rect, - *password_form)); - } +bool PasswordGenerationManager::shouldAddDecorationTo( + const WebKit::WebInputElement& element) { + return element.isPasswordField(); +} + +bool PasswordGenerationManager::visibleByDefault() { + return false; +} + +WebKit::WebCString PasswordGenerationManager::imageNameForNormalState() { + return WebKit::WebCString("generatePassword"); +} + +WebKit::WebCString PasswordGenerationManager::imageNameForDisabledState() { + return imageNameForNormalState(); +} + +WebKit::WebCString PasswordGenerationManager::imageNameForReadOnlyState() { + return imageNameForNormalState(); +} + +void PasswordGenerationManager::handleClick(WebKit::WebInputElement& element) { + gfx::Rect rect(element.decorationElementFor(this).boundsInViewportSpace()); + webkit::forms::PasswordForm* password_form( + webkit::forms::PasswordFormDomManager::CreatePasswordForm( + element.form())); + if (password_form) { + Send(new AutofillHostMsg_ShowPasswordGenerationPopup(routing_id(), + rect, + *password_form)); } } +void PasswordGenerationManager::willDetach( + const WebKit::WebInputElement& element) { + // No implementation +} + bool PasswordGenerationManager::OnMessageReceived(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(PasswordGenerationManager, message) @@ -105,9 +134,8 @@ bool PasswordGenerationManager::OnMessageReceived(const IPC::Message& message) { } void PasswordGenerationManager::OnPasswordAccepted(const string16& password) { - for (std::vector<WebKit::WebInputElement>::iterator it = - account_creation_elements_.second.begin(); - it != account_creation_elements_.second.end(); ++it) { + for (std::vector<WebKit::WebInputElement>::iterator it = passwords_.begin(); + it != passwords_.end(); ++it) { it->setValue(password); it->setAutofilled(true); } diff --git a/chrome/renderer/autofill/password_generation_manager.h b/chrome/renderer/autofill/password_generation_manager.h index 8aa656f..e22531e 100644 --- a/chrome/renderer/autofill/password_generation_manager.h +++ b/chrome/renderer/autofill/password_generation_manager.h @@ -12,23 +12,28 @@ #include "content/public/renderer/render_view_observer.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputElement.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebTextFieldDecoratorClient.h" + +namespace WebKit { +class WebCString; +class WebDocument; +} namespace autofill { // This class is responsible for controlling communication for password // generation between the browser (which shows the popup and generates -// passwords) and WebKit (determines which fields are for account signup and -// fills in the generated passwords). Currently the WebKit part is not -// implemented. -class PasswordGenerationManager : public content::RenderViewObserver { +// passwords) and WebKit (shows the generation icon in the password field). +class PasswordGenerationManager : public content::RenderViewObserver, + public WebKit::WebTextFieldDecoratorClient { public: explicit PasswordGenerationManager(content::RenderView* render_view); virtual ~PasswordGenerationManager(); protected: - // Returns true if this frame is one that we should consider analyzing. + // Returns true if this document is one that we should consider analyzing. // Virtual so that it can be overriden during testing. - virtual bool ShouldAnalyzeFrame(const WebKit::WebFrame& frame) const; + virtual bool ShouldAnalyzeDocument(const WebKit::WebDocument& document) const; // RenderViewObserver: virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; @@ -36,7 +41,16 @@ class PasswordGenerationManager : public content::RenderViewObserver { private: // RenderViewObserver: virtual void DidFinishDocumentLoad(WebKit::WebFrame* frame) OVERRIDE; - virtual void FocusedNodeChanged(const WebKit::WebNode& node) OVERRIDE; + + // WebTextFieldDecoratorClient: + virtual bool shouldAddDecorationTo( + const WebKit::WebInputElement& element) OVERRIDE; + virtual bool visibleByDefault() OVERRIDE; + virtual WebKit::WebCString imageNameForNormalState() OVERRIDE; + virtual WebKit::WebCString imageNameForDisabledState() OVERRIDE; + virtual WebKit::WebCString imageNameForReadOnlyState() OVERRIDE; + virtual void handleClick(WebKit::WebInputElement& element) OVERRIDE; + virtual void willDetach(const WebKit::WebInputElement&) OVERRIDE; // Message handlers. void OnPasswordAccepted(const string16& password); @@ -46,8 +60,7 @@ class PasswordGenerationManager : public content::RenderViewObserver { // with this renderer. bool enabled_; - std::pair<WebKit::WebInputElement, - std::vector<WebKit::WebInputElement> > account_creation_elements_; + std::vector<WebKit::WebInputElement> passwords_; DISALLOW_COPY_AND_ASSIGN(PasswordGenerationManager); }; diff --git a/chrome/renderer/autofill/password_generation_manager_browsertest.cc b/chrome/renderer/autofill/password_generation_manager_browsertest.cc index ce9367f..d51e8c2 100644 --- a/chrome/renderer/autofill/password_generation_manager_browsertest.cc +++ b/chrome/renderer/autofill/password_generation_manager_browsertest.cc @@ -37,7 +37,7 @@ class TestPasswordGenerationManager : public PasswordGenerationManager { } protected: - virtual bool ShouldAnalyzeFrame(const WebKit::WebFrame& frame) const + virtual bool ShouldAnalyzeDocument(const WebKit::WebDocument& document) const OVERRIDE { return true; } @@ -65,6 +65,18 @@ class PasswordGenerationManagerTest : public ChromeRenderViewTest { generation_manager_.reset(new TestPasswordGenerationManager(view_)); } + void SimulateClickOnDecoration(WebKit::WebInputElement* input_element) { + WebKit::WebElement decoration = + input_element->decorationElementFor(generation_manager_.get()); + decoration.simulateClick(); + } + + bool DecorationIsVisible(WebKit::WebInputElement* input_element) { + WebKit::WebElement decoration = + input_element->decorationElementFor(generation_manager_.get()); + return decoration.hasNonEmptyBoundingBox(); + } + protected: scoped_ptr<TestPasswordGenerationManager> generation_manager_; @@ -95,39 +107,36 @@ TEST_F(PasswordGenerationManagerTest, DetectionTest) { document.getElementById(WebString::fromUTF8("password")); ASSERT_FALSE(element.isNull()); WebInputElement password_element = element.to<WebInputElement>(); - EXPECT_EQ(0u, generation_manager_->messages().size()); + EXPECT_FALSE(DecorationIsVisible(&password_element)); LoadHTML(kAccountCreationFormHTML); - // We don't do anything yet because the feature is disabled. + // We don't show the decoration yet because the feature isn't enabled. document = GetMainFrame()->document(); element = document.getElementById(WebString::fromUTF8("first_password")); ASSERT_FALSE(element.isNull()); WebInputElement first_password_element = element.to<WebInputElement>(); - EXPECT_EQ(0u, generation_manager_->messages().size()); element = document.getElementById(WebString::fromUTF8("second_password")); ASSERT_FALSE(element.isNull()); WebInputElement second_password_element = element.to<WebInputElement>(); - EXPECT_EQ(0u, generation_manager_->messages().size()); - SetFocused(first_password_element.to<WebNode>()); - EXPECT_EQ(0u, generation_manager_->messages().size()); + EXPECT_FALSE(DecorationIsVisible(&first_password_element)); // Pretend like password generation was enabled. AutofillMsg_PasswordGenerationEnabled msg(0, true); generation_manager_->OnMessageReceived(msg); - // Now we will send a message once the first password feld is focused. + // Now check that the decoration is visible on the first password field and + // that we send a message after the decoration is clicked. LoadHTML(kAccountCreationFormHTML); document = GetMainFrame()->document(); element = document.getElementById(WebString::fromUTF8("first_password")); ASSERT_FALSE(element.isNull()); first_password_element = element.to<WebInputElement>(); - EXPECT_EQ(0u, generation_manager_->messages().size()); element = document.getElementById(WebString::fromUTF8("second_password")); ASSERT_FALSE(element.isNull()); second_password_element = element.to<WebInputElement>(); - EXPECT_EQ(0u, generation_manager_->messages().size()); - SetFocused(first_password_element.to<WebNode>()); + EXPECT_TRUE(DecorationIsVisible(&first_password_element)); + SimulateClickOnDecoration(&first_password_element); EXPECT_EQ(1u, generation_manager_->messages().size()); EXPECT_EQ(AutofillHostMsg_ShowPasswordGenerationPopup::ID, generation_manager_->messages()[0]->type()); |