diff options
author | jcampan@chromium.org <jcampan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-11-07 21:35:03 +0000 |
---|---|---|
committer | jcampan@chromium.org <jcampan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-11-07 21:35:03 +0000 |
commit | 0ebf38756f3a68b30fe0d8e9336dbfafda52b5d5 (patch) | |
tree | a9ce0236b330fab3f39124c52fa0c1f184eb3965 /webkit/glue | |
parent | 5e91242859811aef980a929253e6c33eb2cfec6e (diff) | |
download | chromium_src-0ebf38756f3a68b30fe0d8e9336dbfafda52b5d5.zip chromium_src-0ebf38756f3a68b30fe0d8e9336dbfafda52b5d5.tar.gz chromium_src-0ebf38756f3a68b30fe0d8e9336dbfafda52b5d5.tar.bz2 |
Landing this again as I cannot reproduce the perf regression locally.
Will investigate on the bot.
TBR=nsylvain
Review URL: http://codereview.chromium.org/9700
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@5018 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/glue')
-rw-r--r-- | webkit/glue/SConscript | 1 | ||||
-rw-r--r-- | webkit/glue/autocomplete_input_listener.h | 1 | ||||
-rw-r--r-- | webkit/glue/chrome_client_impl.cc | 8 | ||||
-rw-r--r-- | webkit/glue/chrome_client_impl.h | 3 | ||||
-rw-r--r-- | webkit/glue/form_autocomplete_listener.cc | 37 | ||||
-rw-r--r-- | webkit/glue/form_autocomplete_listener.h | 46 | ||||
-rw-r--r-- | webkit/glue/password_autocomplete_listener.cc | 1 | ||||
-rw-r--r-- | webkit/glue/webframeloaderclient_impl.cc | 60 | ||||
-rw-r--r-- | webkit/glue/webframeloaderclient_impl.h | 8 | ||||
-rw-r--r-- | webkit/glue/webplugin_impl_mac.mm | 3 | ||||
-rw-r--r-- | webkit/glue/webview.h | 7 | ||||
-rw-r--r-- | webkit/glue/webview_delegate.h | 11 | ||||
-rw-r--r-- | webkit/glue/webview_impl.cc | 214 | ||||
-rw-r--r-- | webkit/glue/webview_impl.h | 16 |
14 files changed, 403 insertions, 13 deletions
diff --git a/webkit/glue/SConscript b/webkit/glue/SConscript index c82a3c8..0870d6b 100644 --- a/webkit/glue/SConscript +++ b/webkit/glue/SConscript @@ -35,6 +35,7 @@ input_files = [ 'editor_client_impl.cc', 'entity_map.cc', 'event_conversion.cc', + 'form_autocomplete_listener.cc', 'feed_preview.cc', 'glue_util.cc', 'glue_serialize.cc', diff --git a/webkit/glue/autocomplete_input_listener.h b/webkit/glue/autocomplete_input_listener.h index 3b92b86..fe412f1 100644 --- a/webkit/glue/autocomplete_input_listener.h +++ b/webkit/glue/autocomplete_input_listener.h @@ -16,7 +16,6 @@ MSVC_PUSH_WARNING_LEVEL(0); #include "EventListener.h" MSVC_POP_WARNING(); -#undef LOG #include "base/basictypes.h" #include "base/scoped_ptr.h" diff --git a/webkit/glue/chrome_client_impl.cc b/webkit/glue/chrome_client_impl.cc index 387f307..081d4c7 100644 --- a/webkit/glue/chrome_client_impl.cc +++ b/webkit/glue/chrome_client_impl.cc @@ -449,12 +449,14 @@ void ChromeClientImpl::runFileChooser(const WebCore::String& default_path, delegate->RunFileChooser(suggestion, chooser); } -void ChromeClientImpl::popupOpened( - WebCore::FramelessScrollView* popup_view, const WebCore::IntRect& bounds) { +void ChromeClientImpl::popupOpened(WebCore::FramelessScrollView* popup_view, + const WebCore::IntRect& bounds, + bool focus_on_show) { WebViewDelegate* d = webview_->delegate(); if (d) { WebWidgetImpl* webwidget = - static_cast<WebWidgetImpl*>(d->CreatePopupWidget(webview_)); + static_cast<WebWidgetImpl*>(d->CreatePopupWidget(webview_, + focus_on_show)); webwidget->Init(popup_view, webkit_glue::FromIntRect(bounds)); } } diff --git a/webkit/glue/chrome_client_impl.h b/webkit/glue/chrome_client_impl.h index 88cf83c..7bb132b 100644 --- a/webkit/glue/chrome_client_impl.h +++ b/webkit/glue/chrome_client_impl.h @@ -115,7 +115,8 @@ public: virtual void runFileChooser(const WebCore::String&, PassRefPtr<WebCore::FileChooser>); virtual void popupOpened(WebCore::FramelessScrollView* popup_view, - const WebCore::IntRect& bounds); + const WebCore::IntRect& bounds, + bool focus_on_show); void SetCursor(const WebCursor& cursor); diff --git a/webkit/glue/form_autocomplete_listener.cc b/webkit/glue/form_autocomplete_listener.cc new file mode 100644 index 0000000..aaaf0f70 --- /dev/null +++ b/webkit/glue/form_autocomplete_listener.cc @@ -0,0 +1,37 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "config.h" + +#include "webkit/glue/form_autocomplete_listener.h" + +MSVC_PUSH_WARNING_LEVEL(0); +#include "HTMLInputElement.h" +MSVC_POP_WARNING(); + +#undef LOG + +#include "webkit/glue/autocomplete_input_listener.h" +#include "webkit/glue/glue_util.h" +#include "webkit/glue/webview_delegate.h" + +namespace webkit_glue { + +FormAutocompleteListener::FormAutocompleteListener( + WebViewDelegate* webview_delegate, + WebCore::HTMLInputElement* input_element) + : AutocompleteInputListener(new HTMLInputDelegate(input_element)), + webview_delegate_(webview_delegate), + name_(webkit_glue::StringToStdWString(input_element->name().string())), + node_id_(reinterpret_cast<int64>(input_element)) { + DCHECK(input_element->isTextField() && !input_element->isPasswordField() && + input_element->autoComplete()); +} + +void FormAutocompleteListener::OnInlineAutocompleteNeeded( + const std::wstring& user_input) { + webview_delegate_->QueryFormFieldAutofill(name_, user_input, node_id_); +} + +} // namespace diff --git a/webkit/glue/form_autocomplete_listener.h b/webkit/glue/form_autocomplete_listener.h new file mode 100644 index 0000000..e55522e --- /dev/null +++ b/webkit/glue/form_autocomplete_listener.h @@ -0,0 +1,46 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef WEBKIT_GLUE_FORM_AUTOCOMPLETE_LISTENER_ +#define WEBKIT_GLUE_FORM_AUTOCOMPLETE_LISTENER_ + +#include <string> + +#include "webkit/glue/autocomplete_input_listener.h" + +class WebViewDelegate; + +namespace webkit_glue { + +// This class listens for the user typing in a text input in a form and queries +// the browser for autofill information. + +class FormAutocompleteListener : public AutocompleteInputListener { + public: + FormAutocompleteListener(WebViewDelegate* webview_delegate, + WebCore::HTMLInputElement* input_element); + virtual ~FormAutocompleteListener() { } + + // AutocompleteInputListener implementation. + virtual void OnBlur(const std::wstring& user_input) { } + virtual void OnInlineAutocompleteNeeded(const std::wstring& user_input); + + private: + // The delegate associated with the WebView that contains thhe input we are + // listening to. + WebViewDelegate* webview_delegate_; + + // The name of the input node we are listening to. + std::wstring name_; + + // An id to represent the input element. That ID is passed to the call that + // queries for suggestions. + int64 node_id_; + + DISALLOW_COPY_AND_ASSIGN(FormAutocompleteListener); +}; + +} // webkit_glue + +#endif // WEBKIT_GLUE_FORM_AUTOCOMPLETE_LISTENER_ diff --git a/webkit/glue/password_autocomplete_listener.cc b/webkit/glue/password_autocomplete_listener.cc index aaf6125..0a88ab3 100644 --- a/webkit/glue/password_autocomplete_listener.cc +++ b/webkit/glue/password_autocomplete_listener.cc @@ -6,6 +6,7 @@ // component. #include "webkit/glue/password_autocomplete_listener.h" +#undef LOG #include "base/logging.h" namespace webkit_glue { diff --git a/webkit/glue/webframeloaderclient_impl.cc b/webkit/glue/webframeloaderclient_impl.cc index 8138900..06e0645 100644 --- a/webkit/glue/webframeloaderclient_impl.cc +++ b/webkit/glue/webframeloaderclient_impl.cc @@ -16,6 +16,9 @@ MSVC_PUSH_WARNING_LEVEL(0); #include "Element.h" #include "HistoryItem.h" #include "HTMLFormElement.h" // needed by FormState.h +#include "HTMLFormControlElement.h" +#include "HTMLInputElement.h" +#include "HTMLNames.h" #include "FormState.h" #include "FrameLoader.h" #include "FrameLoadRequest.h" @@ -39,8 +42,9 @@ MSVC_POP_WARNING(); #if defined(OS_WIN) #include "webkit/activex_shim/activex_shared.h" #endif -#include "webkit/glue/webframeloaderclient_impl.h" #include "webkit/glue/alt_404_page_resource_fetcher.h" +#include "webkit/glue/autocomplete_input_listener.h" +#include "webkit/glue/form_autocomplete_listener.h" #include "webkit/glue/glue_util.h" #include "webkit/glue/password_form_dom_manager.h" #include "webkit/glue/plugins/plugin_list.h" @@ -48,6 +52,7 @@ MSVC_POP_WARNING(); #include "webkit/glue/webdatasource_impl.h" #include "webkit/glue/webdocumentloader_impl.h" #include "webkit/glue/weberror_impl.h" +#include "webkit/glue/webframeloaderclient_impl.h" #include "webkit/glue/webhistoryitem_impl.h" #include "webkit/glue/webkit_glue.h" #include "webkit/glue/webplugin_impl.h" @@ -351,10 +356,26 @@ void WebFrameLoaderClient::dispatchDidFinishDocumentLoad() { if (!form->autoComplete()) continue; + std::set<std::wstring> password_related_fields; scoped_ptr<PasswordForm> data( PasswordFormDomManager::CreatePasswordForm(form)); - if (data.get()) + if (data.get()) { actions.push_back(*data); + // Let's remember the names of password related fields so we do not + // autofill them with the regular form autofill. + DCHECK(!data->username_element.empty()); + DCHECK(!data->password_element.empty()); + password_related_fields.insert(data->username_element); + password_related_fields.insert(data->password_element); + if (!data->old_password_element.empty()) + password_related_fields.insert(data->old_password_element); + } + + // Now let's register for any text input. + // TODO(jcampan): bug #3847 merge password and form autofill so we + // traverse the form elements only once. + // Disabling the autofill to investigate the perf regression on build bot. + // RegisterAutofillListeners(form, password_related_fields); } } @@ -686,6 +707,40 @@ NavigationGesture WebFrameLoaderClient::NavigationGestureForLastLoad() { NavigationGestureAuto; } +void WebFrameLoaderClient::RegisterAutofillListeners( + WebCore::HTMLFormElement* form, + const std::set<std::wstring>& excluded_fields) { + + WebViewDelegate* webview_delegate = webframe_->webview_impl()->delegate(); + if (!webview_delegate) + return; + + for (size_t i = 0; i < form->formElements.size(); i++) { + WebCore::HTMLFormControlElement* form_element = form->formElements[i]; + if (!form_element->hasLocalName(WebCore::HTMLNames::inputTag)) + continue; + + WebCore::HTMLInputElement* input_element = + static_cast<WebCore::HTMLInputElement*>(form_element); + if (!input_element->isEnabled() || !input_element->isTextField() || + input_element->isPasswordField() || !input_element->autoComplete()) { + continue; + } + + std::wstring name = webkit_glue::StringToStdWString(input_element->name()); + if (excluded_fields.find(name) != excluded_fields.end()) + continue; + +#if !defined(OS_MACOSX) + // FIXME on Mac + webkit_glue::FormAutocompleteListener* listener = + new webkit_glue::FormAutocompleteListener(webview_delegate, + input_element); + webkit_glue::AttachForInlineAutocomplete(input_element, listener); +#endif + } +} + void WebFrameLoaderClient::dispatchDidReceiveTitle(const String& title) { WebViewImpl* webview = webframe_->webview_impl(); WebViewDelegate* d = webview->delegate(); @@ -1478,4 +1533,3 @@ bool WebFrameLoaderClient::ActionSpecifiesDisposition( *disposition = shift ? NEW_WINDOW : SAVE_TO_DISK; return true; } - diff --git a/webkit/glue/webframeloaderclient_impl.h b/webkit/glue/webframeloaderclient_impl.h index 20b12ee..6010ba8 100644 --- a/webkit/glue/webframeloaderclient_impl.h +++ b/webkit/glue/webframeloaderclient_impl.h @@ -5,6 +5,8 @@ #ifndef WEBKIT_GLUE_WEBFRAMELOADERCLIENT_IMPL_H__ #define WEBKIT_GLUE_WEBFRAMELOADERCLIENT_IMPL_H__ +#include <set> + #include "base/compiler_specific.h" MSVC_PUSH_WARNING_LEVEL(0); @@ -18,6 +20,7 @@ MSVC_POP_WARNING(); namespace WebCore { class Frame; +class HTMLFormElement; class Widget; } @@ -209,6 +212,11 @@ class WebFrameLoaderClient : public WebCore::FrameLoaderClient { // otherwise returns NavigationGestureUnknown. NavigationGesture NavigationGestureForLastLoad(); + // Registers the text input fields in the passed form for autofill, with the + // exclusion of any field whose name is contained in |excluded_fields|. + void RegisterAutofillListeners(WebCore::HTMLFormElement* form, + const std::set<std::wstring>& excluded_fields); + // The WebFrame that owns this object and manages its lifetime. Therefore, // the web frame object is guaranteed to exist. WebFrameImpl* webframe_; diff --git a/webkit/glue/webplugin_impl_mac.mm b/webkit/glue/webplugin_impl_mac.mm index 191ebb7..1a420ea 100644 --- a/webkit/glue/webplugin_impl_mac.mm +++ b/webkit/glue/webplugin_impl_mac.mm @@ -4,6 +4,9 @@ #include "config.h" +#include "wtf/ASCIICType.h" + +#undef LOG #include "webkit/glue/webplugin_impl.h" // TODO(pinkerton): all of this needs to be filled in. webplugin_impl.cc has diff --git a/webkit/glue/webview.h b/webkit/glue/webview.h index e47ad0e..1c67c4f4 100644 --- a/webkit/glue/webview.h +++ b/webkit/glue/webview.h @@ -6,6 +6,7 @@ #define WEBKIT_GLUE_WEBVIEW_H__ #include <string> +#include <vector> #include "base/basictypes.h" #include "base/ref_counted.h" @@ -195,6 +196,12 @@ class WebView : public WebWidget { virtual void DragTargetDrop( int client_x, int client_y, int screen_x, int screen_y) = 0; + // Notifies the webview that autofill suggestions are available for a node. + virtual void AutofillSuggestionsForNode( + int64 node_id, + const std::vector<std::wstring>& suggestions, + int default_suggestion_index) = 0; + private: DISALLOW_EVIL_CONSTRUCTORS(WebView); }; diff --git a/webkit/glue/webview_delegate.h b/webkit/glue/webview_delegate.h index 97944dd..1ce50c5 100644 --- a/webkit/glue/webview_delegate.h +++ b/webkit/glue/webview_delegate.h @@ -108,7 +108,8 @@ class WebViewDelegate : virtual public WebWidgetDelegate { // This method is called to create a new WebWidget to act as a popup // (like a drop-down menu). - virtual WebWidget* CreatePopupWidget(WebView* webview) { + virtual WebWidget* CreatePopupWidget(WebView* webview, + bool focus_on_show) { return NULL; } @@ -457,6 +458,14 @@ class WebViewDelegate : virtual public WebWidgetDelegate { virtual void OnUnloadListenerChanged(WebView* webview, WebFrame* webframe) { } + // Queries the browser for suggestions to be shown for the form text field + // named |field_name|. |text| is the text entered by the user so far and + // |node_id| is the id of the node of the input field. + virtual void QueryFormFieldAutofill(const std::wstring& field_name, + const std::wstring& text, + int64 node_id) { + } + // UIDelegate -------------------------------------------------------------- // Asks the browser to show a modal HTML dialog. The dialog is passed the diff --git a/webkit/glue/webview_impl.cc b/webkit/glue/webview_impl.cc index 6375fa3..c807b31 100644 --- a/webkit/glue/webview_impl.cc +++ b/webkit/glue/webview_impl.cc @@ -35,6 +35,7 @@ #include "base/compiler_specific.h" MSVC_PUSH_WARNING_LEVEL(0); +#include "CSSStyleSelector.h" #if defined(OS_WIN) #include "Cursor.h" #endif @@ -50,20 +51,25 @@ MSVC_PUSH_WARNING_LEVEL(0); #include "FrameTree.h" #include "FrameView.h" #include "GraphicsContext.h" +#include "HTMLNames.h" +#include "HTMLInputElement.h" #include "HitTestResult.h" #include "Image.h" #include "InspectorController.h" #include "IntRect.h" #include "KeyboardEvent.h" #include "MIMETypeRegistry.h" +#include "NodeRenderStyle.h" #include "Page.h" #include "PlatformKeyboardEvent.h" #include "PlatformMouseEvent.h" #include "PlatformWheelEvent.h" #include "PluginInfoStore.h" +#include "PopupMenuClient.h" #if defined(OS_WIN) #include "RenderThemeWin.h" #endif +#include "RenderView.h" #include "ResourceHandle.h" #include "SelectionController.h" #include "Settings.h" @@ -94,6 +100,7 @@ MSVC_POP_WARNING(); #include "webkit/glue/webview_delegate.h" #include "webkit/glue/webview_impl.h" #include "webkit/glue/webwidget_impl.h" +#include "webkit/port/platform/chromium/PopupMenuChromium.h" #include "webkit/port/platform/graphics/PlatformContextSkia.h" // Get rid of WTF's pow define so we can use std::pow. @@ -115,6 +122,126 @@ static const double kMaxTextSizeMultiplier = 3.0; static const WebCore::DragOperation kDropTargetOperation = static_cast<WebCore::DragOperation>(DragOperationCopy | DragOperationLink); +// AutocompletePopupMenuClient +class AutocompletePopupMenuClient + : public RefCounted<AutocompletePopupMenuClient>, + public WebCore::PopupMenuClient { + public: + AutocompletePopupMenuClient(WebViewImpl* webview, + WebCore::HTMLInputElement* text_field, + const std::vector<std::wstring>& suggestions, + int default_suggestion_index) + : text_field_(text_field), + selected_index_(default_suggestion_index), + webview_(webview) { + for (std::vector<std::wstring>::const_iterator iter = suggestions.begin(); + iter != suggestions.end(); ++iter) { + suggestions_.push_back(webkit_glue::StdWStringToString(*iter)); + } + } + virtual ~AutocompletePopupMenuClient() { + } + + virtual void valueChanged(unsigned listIndex, bool fireEvents = true) { + text_field_->setValue(suggestions_[listIndex]); + } + + virtual WebCore::String itemText(unsigned list_index) const { + return suggestions_[list_index]; + } + + virtual bool itemIsEnabled(unsigned listIndex) const { + return true; + } + + virtual PopupMenuStyle itemStyle(unsigned listIndex) const { + return menuStyle(); + } + + virtual PopupMenuStyle menuStyle() const { + RenderStyle* style = text_field_->renderStyle() ? + text_field_->renderStyle() : + text_field_->computedStyle(); + return PopupMenuStyle(style->color(), Color::white, style->font(), + style->visibility() == VISIBLE); + } + + virtual int clientInsetLeft() const { + return 0; + } + virtual int clientInsetRight() const { + return 0; + } + virtual int clientPaddingLeft() const { +#if defined(OS_WIN) + return theme()->popupInternalPaddingLeft(text_field_->computedStyle()); +#else + NOTIMPLEMENTED(); + return 0; +#endif + } + virtual int clientPaddingRight() const { +#if defined(OS_WIN) + return theme()->popupInternalPaddingRight(text_field_->computedStyle()); +#else + NOTIMPLEMENTED(); + return 0; +#endif + } + virtual int listSize() const { + return suggestions_.size(); + } + virtual int selectedIndex() const { + return selected_index_; + } + virtual void hidePopup() { + webview_->HideAutoCompletePopup(); + } + virtual bool itemIsSeparator(unsigned listIndex) const { + return false; + } + virtual bool itemIsLabel(unsigned listIndex) const { + return false; + } + virtual bool itemIsSelected(unsigned listIndex) const { + return false; + } + virtual bool shouldPopOver() const { + return false; + } + virtual bool valueShouldChangeOnHotTrack() const { + return false; + } + + virtual FontSelector* fontSelector() const { + return text_field_->document()->styleSelector()->fontSelector(); + } + + virtual void setTextFromItem(unsigned listIndex) { + text_field_->setValue(suggestions_[listIndex]); + } + + virtual HostWindow* hostWindow() const { + return text_field_->document()->view()->hostWindow(); + } + + virtual PassRefPtr<Scrollbar> createScrollbar( + ScrollbarClient* client, + ScrollbarOrientation orientation, + ScrollbarControlSize size) { + RefPtr<Scrollbar> widget = Scrollbar::createNativeScrollbar(client, + orientation, + size); + return widget.release(); + } + + private: + RefPtr<WebCore::HTMLInputElement> text_field_; + std::vector<WebCore::String> suggestions_; + int selected_index_; + WebViewImpl* webview_; +}; + // WebView ---------------------------------------------------------------- /*static*/ @@ -292,6 +419,18 @@ bool WebViewImpl::KeyEvent(const WebKeyboardEvent& event) { // event. suppress_next_keypress_event_ = false; + // Give autocomplete a chance to consume the key events it is interested in. + if (autocomplete_popup_ && + autocomplete_popup_->isInterestedInEventForKey(event.key_code)) { + if (autocomplete_popup_->handleKeyEvent(MakePlatformKeyboardEvent(event))) + return true; + return false; + } + + // A new key being pressed should hide the popup. + if (event.type == WebInputEvent::KEY_DOWN) + HideAutoCompletePopup(); + Frame* frame = GetFocusedWebCoreFrame(); if (!frame) return false; @@ -714,7 +853,6 @@ bool WebViewImpl::HandleInputEvent(const WebInputEvent* input_event) { // we're done. if (doing_drag_and_drop_) return true; - // TODO(eseidel): Remove g_current_input_event. // This only exists to allow ChromeClient::show() to know which mouse button // triggered a window.open event. @@ -782,6 +920,14 @@ void WebViewImpl::SetBackForwardListSize(int size) { void WebViewImpl::SetFocus(bool enable) { if (enable) { + // Hide the popup menu if any. + // TODO(jcampan): bug #3844: we should do that when we lose focus. The + // reason we are not doing it is because when clicking on the autofill + // popup, the page first loses focus before the mouse click is sent to the + // popup. So if we close when the focus is lost, the mouse click does not + // do anything. + HideAutoCompletePopup(); + // Getting the focused frame will have the side-effect of setting the main // frame as the focused frame if it is not already focused. Otherwise, if // there is already a focused frame, then this does nothing. @@ -803,8 +949,6 @@ void WebViewImpl::SetFocus(bool enable) { // updated below. ReleaseFocusReferences(); - // Clear focus on the currently focused frame if any. - if (!main_frame_) return; @@ -1018,7 +1162,8 @@ void WebViewImpl::SetInitialFocus(bool reverse) { // We have to set the key type explicitly to avoid an assert in the // KeyboardEvent constructor. platform_event.SetKeyType(PlatformKeyboardEvent::RawKeyDown); - RefPtr<KeyboardEvent> webkit_event = KeyboardEvent::create(platform_event, NULL); + RefPtr<KeyboardEvent> webkit_event = KeyboardEvent::create(platform_event, + NULL); page()->focusController()->setInitialFocus( reverse ? WebCore::FocusDirectionBackward : WebCore::FocusDirectionForward, @@ -1331,6 +1476,59 @@ SearchableFormData* WebViewImpl::CreateSearchableFormDataForFocusedNode() { return NULL; } +void WebViewImpl::AutofillSuggestionsForNode( + int64 node_id, + const std::vector<std::wstring>& suggestions, + int default_suggestion_index) { + if (!main_frame_ || suggestions.empty()) + return; + + DCHECK(default_suggestion_index < static_cast<int>(suggestions.size())); + + Frame* frame = main_frame_->frame(); + if (!frame) + return; + + if (RefPtr<Frame> focused = + frame->page()->focusController()->focusedFrame()) { + RefPtr<Document> document = focused->document(); + if (!document.get()) + return; + + RefPtr<Node> focused_node = document->focusedNode(); + // If the node for which we queried the autofill suggestions is not the + // focused node, then we have nothing to do. + // TODO(jcampan): also check the carret is at the end and that the text has + // not changed. + if (!focused_node.get() || + reinterpret_cast<int64>(focused_node.get()) != node_id) + return; + + if (!focused_node->hasTagName(WebCore::HTMLNames::inputTag)) { + NOTREACHED(); + return; + } + + WebCore::HTMLInputElement* input_elem = + static_cast<WebCore::HTMLInputElement*>(focused_node.get()); + // Hide any current autocomplete popup. + HideAutoCompletePopup(); + + if (suggestions.size() > 0) { + autocomplete_popup_client_ = + adoptRef(new AutocompletePopupMenuClient(this, input_elem, + suggestions, + default_suggestion_index)); + // Autocomplete popup does not get focused. We need the page to still + // have focus so the user can keep typing when the popup is showing. + autocomplete_popup_ = + WebCore::PopupContainer::create(autocomplete_popup_client_.get(), + false); + autocomplete_popup_->show(focused_node->getRect(), frame->view(), 0); + } + } +} + void WebViewImpl::DidCommitLoad(bool* is_new_navigation) { if (is_new_navigation) *is_new_navigation = observed_new_navigation_; @@ -1479,3 +1677,11 @@ void WebViewImpl::DeleteImageResourceFetcher(ImageResourceFetcher* fetcher) { // deletion. MessageLoop::current()->DeleteSoon(FROM_HERE, fetcher); } + +void WebViewImpl::HideAutoCompletePopup() { + if (autocomplete_popup_) { + autocomplete_popup_->hidePopup(); + autocomplete_popup_.clear(); + autocomplete_popup_client_.clear(); + } +} diff --git a/webkit/glue/webview_impl.h b/webkit/glue/webview_impl.h index da0d533..83cddebd 100644 --- a/webkit/glue/webview_impl.h +++ b/webkit/glue/webview_impl.h @@ -27,10 +27,12 @@ class HistoryItem; class KeyboardEvent; class Page; class PlatformKeyboardEvent; +class PopupContainer; class Range; class Widget; } +class AutocompletePopupMenuClient; class ImageResourceFetcher; class SearchableFormData; struct WebDropData; @@ -98,6 +100,10 @@ class WebViewImpl : public WebView, public WebCore::BackForwardListClient { virtual void DragTargetDragLeave(); virtual void DragTargetDrop( int client_x, int client_y, int screen_x, int screen_y); + virtual void AutofillSuggestionsForNode( + int64 node_id, + const std::vector<std::wstring>& suggestions, + int default_suggestion_index); // WebViewImpl @@ -178,6 +184,9 @@ class WebViewImpl : public WebView, public WebCore::BackForwardListClient { bool errored, const SkBitmap& image); + // Hides the autocomplete popup if it is showing. + void HideAutoCompletePopup(); + protected: friend class WebView; // So WebView::Create can call our constructor @@ -287,6 +296,13 @@ class WebViewImpl : public WebView, public WebCore::BackForwardListClient { // Represents whether or not this object should process incoming IME events. bool ime_accept_events_; + // The currently shown autocomplete popup. + RefPtr<WebCore::PopupContainer> autocomplete_popup_; + + // The popup client of the currently shown autocomplete popup. Necessary for + // managing the life of the client. + RefPtr<AutocompletePopupMenuClient> autocomplete_popup_client_; + // HACK: current_input_event is for ChromeClientImpl::show(), until we can fix // WebKit to pass enough information up into ChromeClient::show() so we can // decide if the window.open event was caused by a middle-mouse click |