diff options
author | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-15 00:03:51 +0000 |
---|---|---|
committer | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-15 00:03:51 +0000 |
commit | 676126f7e4583705e6a381e1b35309ea8242c224 (patch) | |
tree | a690a9752c5864a2f44a5143a15b36894d14803e /chrome | |
parent | ec8ec84a6ad81b3cae8517098e9f22c7a30921ea (diff) | |
download | chromium_src-676126f7e4583705e6a381e1b35309ea8242c224.zip chromium_src-676126f7e4583705e6a381e1b35309ea8242c224.tar.gz chromium_src-676126f7e4583705e6a381e1b35309ea8242c224.tar.bz2 |
Introduce RenderView::Observer interface so that RenderView doesn't have to know about the details of every feature. Observers get to filter and send IPC messages, and basic notifications of frame related events.I've moved over AutoFill related classes, and also made AutoFillManager implement the new WebAutoFillClient interface. For the rest of the classes, they implement the interface just for message filtering.
Review URL: http://codereview.chromium.org/6151011
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@71517 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
28 files changed, 772 insertions, 794 deletions
diff --git a/chrome/chrome_renderer.gypi b/chrome/chrome_renderer.gypi index ebbd838..f1b33f6 100644 --- a/chrome/chrome_renderer.gypi +++ b/chrome/chrome_renderer.gypi @@ -164,6 +164,8 @@ 'renderer/render_view.cc', 'renderer/render_view_linux.cc', 'renderer/render_view.h', + 'renderer/render_view_observer.cc', + 'renderer/render_view_observer.h', 'renderer/render_widget.cc', 'renderer/render_widget.h', 'renderer/render_widget_fullscreen.cc', diff --git a/chrome/renderer/autofill_helper.cc b/chrome/renderer/autofill_helper.cc index b383504..a429577 100644 --- a/chrome/renderer/autofill_helper.cc +++ b/chrome/renderer/autofill_helper.cc @@ -7,7 +7,9 @@ #include "app/l10n_util.h" #include "base/utf_string_conversions.h" #include "chrome/common/chrome_constants.h" +#include "chrome/common/render_messages.h" #include "chrome/renderer/form_manager.h" +#include "chrome/renderer/password_autocomplete_manager.h" #include "chrome/renderer/render_view.h" #include "grit/generated_resources.h" #include "third_party/WebKit/WebKit/chromium/public/WebDocument.h" @@ -36,34 +38,168 @@ const size_t kMaximumTextSizeForAutoFill = 1000; } // namespace -AutoFillHelper::AutoFillHelper(RenderView* render_view) - : render_view_(render_view), +AutoFillHelper::AutoFillHelper( + RenderView* render_view, + PasswordAutocompleteManager* password_autocomplete_manager) + : RenderViewObserver(render_view), + password_autocomplete_manager_(password_autocomplete_manager), autofill_query_id_(0), autofill_action_(AUTOFILL_NONE), display_warning_if_disabled_(false), was_query_node_autofilled_(false), suggestions_clear_index_(-1), - suggestions_options_index_(-1) { + suggestions_options_index_(-1), + ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { } -void AutoFillHelper::RemoveAutocompleteSuggestion(const WebString& name, - const WebString& value) { +bool AutoFillHelper::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(AutoFillHelper, message) + IPC_MESSAGE_HANDLER(ViewMsg_AutoFillSuggestionsReturned, + OnSuggestionsReturned) + IPC_MESSAGE_HANDLER(ViewMsg_AutoFillFormDataFilled, OnFormDataFilled) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void AutoFillHelper::DidFinishDocumentLoad(WebKit::WebFrame* frame) { + // The document has now been fully loaded. Scan for forms to be sent up to + // the browser. + form_manager_.ExtractForms(frame); + SendForms(frame); +} + +void AutoFillHelper::FrameDetached(WebKit::WebFrame* frame) { + form_manager_.ResetFrame(frame); +} + +void AutoFillHelper::FrameWillClose(WebKit::WebFrame* frame) { + form_manager_.ResetFrame(frame); +} + +void AutoFillHelper::FrameTranslated(WebKit::WebFrame* frame) { + // The page is translated, so try to extract the form data again. + DidFinishDocumentLoad(frame); +} + +bool AutoFillHelper::InputElementClicked(const WebInputElement& element, + bool was_focused, + bool is_focused) { + if (was_focused) + ShowSuggestions(element, true, false, true); + return false; +} + +void AutoFillHelper::didAcceptAutoFillSuggestion(const WebKit::WebNode& node, + const WebKit::WebString& value, + const WebKit::WebString& label, + int unique_id, + unsigned index) { + if (suggestions_options_index_ != -1 && + index == static_cast<unsigned>(suggestions_options_index_)) { + // User selected 'AutoFill Options'. + Send(new ViewHostMsg_ShowAutoFillDialog(routing_id())); + } else if (suggestions_clear_index_ != -1 && + index == static_cast<unsigned>(suggestions_clear_index_)) { + // User selected 'Clear form'. + form_manager_.ClearFormWithNode(node); + } else if (!unique_id) { + // User selected an Autocomplete entry, so we fill directly. + WebInputElement element = node.toConst<WebInputElement>(); + + string16 substring = value; + substring = substring.substr(0, element.maxLength()); + element.setValue(substring); + + WebFrame* webframe = node.document().frame(); + if (webframe) + webframe->notifiyPasswordListenerOfAutocomplete(element); + } else { + // Fill the values for the whole form. + FillAutoFillFormData(node, unique_id, AUTOFILL_FILL); + } + + suggestions_clear_index_ = -1; + suggestions_options_index_ = -1; +} + +void AutoFillHelper::didSelectAutoFillSuggestion(const WebKit::WebNode& node, + const WebKit::WebString& value, + const WebKit::WebString& label, + int unique_id) { + DCHECK_GE(unique_id, 0); + + didClearAutoFillSelection(node); + FillAutoFillFormData(node, unique_id, AUTOFILL_PREVIEW); +} + +void AutoFillHelper::didClearAutoFillSelection(const WebKit::WebNode& node) { + form_manager_.ClearPreviewedFormWithNode(node, was_query_node_autofilled_); +} + +void AutoFillHelper::didAcceptAutocompleteSuggestion( + const WebKit::WebInputElement& user_element) { + bool result = password_autocomplete_manager_->FillPassword(user_element); + // Since this user name was selected from a suggestion list, we should always + // have password for it. + DCHECK(result); +} + +void AutoFillHelper::removeAutocompleteSuggestion( + const WebKit::WebString& name, + const WebKit::WebString& value) { // The index of clear & options will have shifted down. if (suggestions_clear_index_ != -1) suggestions_clear_index_--; if (suggestions_options_index_ != -1) suggestions_options_index_--; - render_view_->Send(new ViewHostMsg_RemoveAutocompleteEntry( - render_view_->routing_id(), name, value)); + Send(new ViewHostMsg_RemoveAutocompleteEntry(routing_id(), name, value)); +} + +void AutoFillHelper::textFieldDidEndEditing( + const WebKit::WebInputElement& element) { + password_autocomplete_manager_->TextFieldDidEndEditing(element); +} + +void AutoFillHelper::textFieldDidChange( + const WebKit::WebInputElement& element) { + // We post a task for doing the AutoFill as the caret position is not set + // properly at this point (http://bugs.webkit.org/show_bug.cgi?id=16976) and + // it is needed to trigger autofill. + method_factory_.RevokeAll(); + MessageLoop::current()->PostTask( + FROM_HERE, + method_factory_.NewRunnableMethod( + &AutoFillHelper::TextFieldDidChangeImpl, element)); +} + +void AutoFillHelper::TextFieldDidChangeImpl( + const WebKit::WebInputElement& element) { + if (password_autocomplete_manager_->TextDidChangeInTextField(element)) + return; + + ShowSuggestions(element, false, true, false); +} + +void AutoFillHelper::textFieldDidReceiveKeyDown( + const WebKit::WebInputElement& element, + const WebKit::WebKeyboardEvent& event) { + password_autocomplete_manager_->TextFieldHandlingKeyDown(element, event); + + if (event.windowsKeyCode == ui::VKEY_DOWN || + event.windowsKeyCode == ui::VKEY_UP) + ShowSuggestions(element, true, true, true); } -void AutoFillHelper::SuggestionsReceived(int query_id, - const std::vector<string16>& values, - const std::vector<string16>& labels, - const std::vector<string16>& icons, - const std::vector<int>& unique_ids) { - WebKit::WebView* web_view = render_view_->webview(); +void AutoFillHelper::OnSuggestionsReturned( + int query_id, + const std::vector<string16>& values, + const std::vector<string16>& labels, + const std::vector<string16>& icons, + const std::vector<int>& unique_ids) { + WebKit::WebView* web_view = render_view()->webview(); if (!web_view || query_id != autofill_query_id_) return; @@ -131,13 +267,12 @@ void AutoFillHelper::SuggestionsReceived(int query_id, autofill_query_node_, v, l, i, ids, separator_index); } - render_view_->Send(new ViewHostMsg_DidShowAutoFillSuggestions( - render_view_->routing_id())); + Send(new ViewHostMsg_DidShowAutoFillSuggestions(routing_id())); } -void AutoFillHelper::FormDataFilled(int query_id, - const webkit_glue::FormData& form) { - if (!render_view_->webview() || query_id != autofill_query_id_) +void AutoFillHelper::OnFormDataFilled( + int query_id, const webkit_glue::FormData& form) { + if (!render_view()->webview() || query_id != autofill_query_id_) return; switch (autofill_action_) { @@ -151,85 +286,7 @@ void AutoFillHelper::FormDataFilled(int query_id, NOTREACHED(); } autofill_action_ = AUTOFILL_NONE; - render_view_->Send(new ViewHostMsg_DidFillAutoFillFormData( - render_view_->routing_id())); -} - -void AutoFillHelper::DidSelectAutoFillSuggestion(const WebNode& node, - int unique_id) { - DCHECK_GE(unique_id, 0); - - DidClearAutoFillSelection(node); - FillAutoFillFormData(node, unique_id, AUTOFILL_PREVIEW); -} - -void AutoFillHelper::DidAcceptAutoFillSuggestion(const WebNode& node, - const WebString& value, - int unique_id, - unsigned index) { - if (suggestions_options_index_ != -1 && - index == static_cast<unsigned>(suggestions_options_index_)) { - // User selected 'AutoFill Options'. - render_view_->Send(new ViewHostMsg_ShowAutoFillDialog( - render_view_->routing_id())); - } else if (suggestions_clear_index_ != -1 && - index == static_cast<unsigned>(suggestions_clear_index_)) { - // User selected 'Clear form'. - form_manager_.ClearFormWithNode(node); - } else if (!unique_id) { - // User selected an Autocomplete entry, so we fill directly. - WebInputElement element = node.toConst<WebInputElement>(); - - string16 substring = value; - substring = substring.substr(0, element.maxLength()); - element.setValue(substring); - - WebFrame* webframe = node.document().frame(); - if (webframe) - webframe->notifiyPasswordListenerOfAutocomplete(element); - } else { - // Fill the values for the whole form. - FillAutoFillFormData(node, unique_id, AUTOFILL_FILL); - } - - suggestions_clear_index_ = -1; - suggestions_options_index_ = -1; -} - -void AutoFillHelper::DidClearAutoFillSelection(const WebNode& node) { - form_manager_.ClearPreviewedFormWithNode(node, was_query_node_autofilled_); -} - -void AutoFillHelper::FrameContentsAvailable(WebFrame* frame) { - form_manager_.ExtractForms(frame); - SendForms(frame); -} - -void AutoFillHelper::FrameWillClose(WebFrame* frame) { - form_manager_.ResetFrame(frame); -} - -void AutoFillHelper::FrameDetached(WebFrame* frame) { - form_manager_.ResetFrame(frame); -} - -void AutoFillHelper::TextDidChangeInTextField(const WebInputElement& element) { - ShowSuggestions(element, false, true, false); -} - -void AutoFillHelper::KeyDownInTextField(const WebInputElement& element, - const WebKeyboardEvent& event) { - if (event.windowsKeyCode == ui::VKEY_DOWN || - event.windowsKeyCode == ui::VKEY_UP) - ShowSuggestions(element, true, true, true); -} - -bool AutoFillHelper::InputElementClicked(const WebInputElement& element, - bool was_focused, - bool is_focused) { - if (was_focused) - ShowSuggestions(element, true, false, true); - return false; + Send(new ViewHostMsg_DidFillAutoFillFormData(routing_id())); } void AutoFillHelper::ShowSuggestions(const WebInputElement& element, @@ -273,8 +330,8 @@ void AutoFillHelper::QueryAutoFillSuggestions( if (!FindFormAndFieldForNode(node, &form, &field)) return; - render_view_->Send(new ViewHostMsg_QueryFormFieldAutoFill( - render_view_->routing_id(), autofill_query_id_, form, field)); + Send(new ViewHostMsg_QueryFormFieldAutoFill( + routing_id(), autofill_query_id_, form, field)); } void AutoFillHelper::FillAutoFillFormData(const WebNode& node, @@ -290,8 +347,8 @@ void AutoFillHelper::FillAutoFillFormData(const WebNode& node, autofill_action_ = action; was_query_node_autofilled_ = field.is_autofilled(); - render_view_->Send(new ViewHostMsg_FillAutoFillFormData( - render_view_->routing_id(), autofill_query_id_, form, field, unique_id)); + Send(new ViewHostMsg_FillAutoFillFormData( + routing_id(), autofill_query_id_, form, field, unique_id)); } void AutoFillHelper::SendForms(WebFrame* frame) { @@ -312,10 +369,8 @@ void AutoFillHelper::SendForms(WebFrame* frame) { } } - if (!forms.empty()) { - render_view_->Send(new ViewHostMsg_FormsSeen(render_view_->routing_id(), - forms)); - } + if (!forms.empty()) + Send(new ViewHostMsg_FormsSeen(routing_id(), forms)); } bool AutoFillHelper::FindFormAndFieldForNode(const WebNode& node, diff --git a/chrome/renderer/autofill_helper.h b/chrome/renderer/autofill_helper.h index c948bcf..d639bd1 100644 --- a/chrome/renderer/autofill_helper.h +++ b/chrome/renderer/autofill_helper.h @@ -10,17 +10,14 @@ #include "base/basictypes.h" #include "base/compiler_specific.h" +#include "base/task.h" #include "chrome/renderer/form_manager.h" #include "chrome/renderer/page_click_listener.h" +#include "chrome/renderer/render_view_observer.h" +#include "third_party/WebKit/WebKit/chromium/public/WebAutoFillClient.h" #include "third_party/WebKit/WebKit/chromium/public/WebNode.h" -class RenderView; - -namespace WebKit { -class WebInputElement; -class WebKeyboardEvent; -class WebString; -} +class PasswordAutocompleteManager; // AutoFillHelper deals with AutoFill related communications between WebKit and // the browser. There is one AutofillHelper per RenderView. @@ -29,63 +26,34 @@ class WebString; // - single text field suggestions, that we usually refer to as Autocomplete // - entire form fill based on one field entry, referred to as form AutoFill. -class AutoFillHelper : public PageClickListener { +class AutoFillHelper : public RenderViewObserver, + public PageClickListener, + public WebKit::WebAutoFillClient { public: - explicit AutoFillHelper(RenderView* render_view); - - // Removes the Autocomplete suggestion |value| for the field named |name|. - void RemoveAutocompleteSuggestion(const WebKit::WebString& name, - const WebKit::WebString& value); - - // Called when we have received AutoFill suggestions from the browser. - void SuggestionsReceived(int query_id, - const std::vector<string16>& values, - const std::vector<string16>& labels, - const std::vector<string16>& icons, - const std::vector<int>& unique_ids); - - // Called when we have received suggestions for an entire form from the - // browser. - void FormDataFilled(int query_id, const webkit_glue::FormData& form); - - // Called by Webkit when the user has selected a suggestion in the popup (this - // happens when the user hovers over an suggestion or navigates the popup with - // the arrow keys). - void DidSelectAutoFillSuggestion(const WebKit::WebNode& node, - int unique_id); - - // Called by Webkit when the user has accepted a suggestion in the popup. - void DidAcceptAutoFillSuggestion(const WebKit::WebNode& node, - const WebKit::WebString& value, - int unique_id, - unsigned index); - - // Called by WebKit when the user has cleared the selection from the AutoFill - // suggestions popup. This happens when a user uses the arrow keys to - // navigate outside the range of possible selections, or when the popup - // closes. - void DidClearAutoFillSelection(const WebKit::WebNode& node); - - // Called when the frame contents are available. Extracts the forms from that - // frame and sends them to the browser for parsing. - void FrameContentsAvailable(WebKit::WebFrame* frame); - - // Called before a frame is closed. Gives us an opportunity to clean up. - // DEPRECATED. - void FrameWillClose(WebKit::WebFrame* frame); - - // Called when |frame| is detached from the view. Gives us an opportunity to - // clean up. - void FrameDetached(WebKit::WebFrame* frame); - - // WebViewClient editor call forwarded by the RenderView. - void TextDidChangeInTextField(const WebKit::WebInputElement& element); - - // WebViewClient editor call forwarded by the RenderView. For lower level - // event translation. Specifically, for down/up key presses in an input - // element. - void KeyDownInTextField(const WebKit::WebInputElement& element, - const WebKit::WebKeyboardEvent& event); + // PasswordAutocompleteManager is guaranteed to outlive AutoFillHelper. + AutoFillHelper(RenderView* render_view, + PasswordAutocompleteManager* password_autocomplete_manager); + + // WebKit::WebAutoFillClient implementation. Public for tests. + virtual void didAcceptAutoFillSuggestion(const WebKit::WebNode& node, + const WebKit::WebString& value, + const WebKit::WebString& label, + int unique_id, + unsigned index); + virtual void didSelectAutoFillSuggestion(const WebKit::WebNode& node, + const WebKit::WebString& value, + const WebKit::WebString& label, + int unique_id); + virtual void didClearAutoFillSelection(const WebKit::WebNode& node); + virtual void didAcceptAutocompleteSuggestion( + const WebKit::WebInputElement& element); + virtual void removeAutocompleteSuggestion(const WebKit::WebString& name, + const WebKit::WebString& value); + virtual void textFieldDidEndEditing(const WebKit::WebInputElement& element); + virtual void textFieldDidChange(const WebKit::WebInputElement& element); + virtual void textFieldDidReceiveKeyDown( + const WebKit::WebInputElement& element, + const WebKit::WebKeyboardEvent& event); private: enum AutoFillAction { @@ -94,11 +62,29 @@ class AutoFillHelper : public PageClickListener { AUTOFILL_PREVIEW, // Preview the AutoFill form data. }; + // RenderView::Observer implementation. + virtual bool OnMessageReceived(const IPC::Message& message); + virtual void DidFinishDocumentLoad(WebKit::WebFrame* frame); + virtual void FrameDetached(WebKit::WebFrame* frame); + virtual void FrameWillClose(WebKit::WebFrame* frame); + virtual void FrameTranslated(WebKit::WebFrame* frame); + // PageClickListener implementation: virtual bool InputElementClicked(const WebKit::WebInputElement& element, bool was_focused, bool is_focused); + void OnSuggestionsReturned(int query_id, + const std::vector<string16>& values, + const std::vector<string16>& labels, + const std::vector<string16>& icons, + const std::vector<int>& unique_ids); + void OnFormDataFilled(int query_id, const webkit_glue::FormData& form); + + // Called in a posted task by textFieldDidChange() to work-around a WebKit bug + // http://bugs.webkit.org/show_bug.cgi?id=16976 + void TextFieldDidChangeImpl(const WebKit::WebInputElement& element); + // Shows the autocomplete suggestions for |element|. // This call is asynchronous and may or may not lead to the showing of a // suggestion popup (no popup is shown if there are no available suggestions). @@ -138,11 +124,10 @@ class AutoFillHelper : public PageClickListener { webkit_glue::FormData* form, webkit_glue::FormField* field) WARN_UNUSED_RESULT; - // Weak reference. - RenderView* render_view_; - FormManager form_manager_; + PasswordAutocompleteManager* password_autocomplete_manager_; + // The ID of the last request sent for form field AutoFill. Used to ignore // out of date responses. int autofill_query_id_; @@ -165,6 +150,8 @@ class AutoFillHelper : public PageClickListener { // The menu index of the "AutoFill options..." menu item. int suggestions_options_index_; + ScopedRunnableMethodFactory<AutoFillHelper> method_factory_; + DISALLOW_COPY_AND_ASSIGN(AutoFillHelper); }; diff --git a/chrome/renderer/device_orientation_dispatcher.cc b/chrome/renderer/device_orientation_dispatcher.cc index edf9d03..d5e443d 100644 --- a/chrome/renderer/device_orientation_dispatcher.cc +++ b/chrome/renderer/device_orientation_dispatcher.cc @@ -4,14 +4,14 @@ #include "chrome/renderer/device_orientation_dispatcher.h" +#include "chrome/common/render_messages.h" #include "chrome/common/render_messages_params.h" -#include "chrome/renderer/render_view.h" #include "third_party/WebKit/WebKit/chromium/public/WebDeviceOrientation.h" #include "third_party/WebKit/WebKit/chromium/public/WebDeviceOrientationController.h" DeviceOrientationDispatcher::DeviceOrientationDispatcher( RenderView* render_view) - : render_view_(render_view), + : RenderViewObserver(render_view), controller_(NULL), started_(false) { } @@ -37,14 +37,12 @@ void DeviceOrientationDispatcher::setController( } void DeviceOrientationDispatcher::startUpdating() { - render_view_->Send(new ViewHostMsg_DeviceOrientation_StartUpdating( - render_view_->routing_id())); + Send(new ViewHostMsg_DeviceOrientation_StartUpdating(routing_id())); started_ = true; } void DeviceOrientationDispatcher::stopUpdating() { - render_view_->Send(new ViewHostMsg_DeviceOrientation_StopUpdating( - render_view_->routing_id())); + Send(new ViewHostMsg_DeviceOrientation_StopUpdating(routing_id())); started_ = false; } diff --git a/chrome/renderer/device_orientation_dispatcher.h b/chrome/renderer/device_orientation_dispatcher.h index 88c1ef5..d60a470 100644 --- a/chrome/renderer/device_orientation_dispatcher.h +++ b/chrome/renderer/device_orientation_dispatcher.h @@ -8,21 +8,21 @@ #include "third_party/WebKit/WebKit/chromium/public/WebDeviceOrientationClient.h" #include "base/scoped_ptr.h" -#include "ipc/ipc_channel.h" +#include "chrome/renderer/render_view_observer.h" -class RenderView; namespace WebKit { class WebDeviceOrientation; } struct ViewMsg_DeviceOrientationUpdated_Params; -class DeviceOrientationDispatcher : public WebKit::WebDeviceOrientationClient, - public IPC::Channel::Listener { +class DeviceOrientationDispatcher : public RenderViewObserver, + public WebKit::WebDeviceOrientationClient { public: - explicit DeviceOrientationDispatcher(RenderView* render_view); + DeviceOrientationDispatcher(RenderView* render_view); virtual ~DeviceOrientationDispatcher(); - // IPC::Channel::Implementation. - bool OnMessageReceived(const IPC::Message& msg); + private: + // RenderView::Observer implementation. + bool OnMessageReceived(const IPC::Message& message); // From WebKit::WebDeviceOrientationClient. virtual void setController( @@ -31,11 +31,9 @@ class DeviceOrientationDispatcher : public WebKit::WebDeviceOrientationClient, virtual void stopUpdating(); virtual WebKit::WebDeviceOrientation lastOrientation() const; - private: void OnDeviceOrientationUpdated( const ViewMsg_DeviceOrientationUpdated_Params& p); - RenderView* render_view_; scoped_ptr<WebKit::WebDeviceOrientationController> controller_; scoped_ptr<WebKit::WebDeviceOrientation> last_orientation_; bool started_; diff --git a/chrome/renderer/devtools_agent.cc b/chrome/renderer/devtools_agent.cc index ca1ef3a..1d88a4d 100644 --- a/chrome/renderer/devtools_agent.cc +++ b/chrome/renderer/devtools_agent.cc @@ -53,24 +53,16 @@ class WebKitClientMessageLoopImpl // static std::map<int, DevToolsAgent*> DevToolsAgent::agent_for_routing_id_; -DevToolsAgent::DevToolsAgent(int routing_id, RenderView* render_view) - : routing_id_(routing_id), - render_view_(render_view) { - agent_for_routing_id_[routing_id] = this; +DevToolsAgent::DevToolsAgent(RenderView* render_view) + : RenderViewObserver(render_view) { + agent_for_routing_id_[routing_id()] = this; CommandLine* cmd = CommandLine::ForCurrentProcess(); - expose_v8_debugger_protocol_ =cmd->HasSwitch(switches::kRemoteShellPort); + expose_v8_debugger_protocol_ = cmd->HasSwitch(switches::kRemoteShellPort); } DevToolsAgent::~DevToolsAgent() { - agent_for_routing_id_.erase(routing_id_); -} - -void DevToolsAgent::OnNavigate() { - WebDevToolsAgent* web_agent = GetWebAgent(); - if (web_agent) { - web_agent->didNavigate(); - } + agent_for_routing_id_.erase(routing_id()); } // Called on the Renderer thread. @@ -85,33 +77,35 @@ bool DevToolsAgent::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER(DevToolsAgentMsg_InspectElement, OnInspectElement) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() + + if (message.type() == ViewMsg_Navigate::ID) + OnNavigate(); // Don't want to swallow the message. + return handled; } void DevToolsAgent::sendMessageToInspectorFrontend( const WebKit::WebString& message) { - IPC::Message* m = new ViewHostMsg_ForwardToDevToolsClient( - routing_id_, - DevToolsClientMsg_DispatchOnInspectorFrontend(message.utf8())); - render_view_->Send(m); + Send(new ViewHostMsg_ForwardToDevToolsClient( + routing_id(), + DevToolsClientMsg_DispatchOnInspectorFrontend(message.utf8()))); } void DevToolsAgent::sendDebuggerOutput(const WebKit::WebString& data) { - IPC::Message* m = new ViewHostMsg_ForwardToDevToolsClient( - routing_id_, - DevToolsClientMsg_DebuggerOutput(data.utf8())); - render_view_->Send(m); + Send(new ViewHostMsg_ForwardToDevToolsClient( + routing_id(), + DevToolsClientMsg_DebuggerOutput(data.utf8()))); } int DevToolsAgent::hostIdentifier() { - return routing_id_; + return routing_id(); } void DevToolsAgent::runtimeFeatureStateChanged( const WebKit::WebString& feature, bool enabled) { - render_view_->Send(new ViewHostMsg_DevToolsRuntimePropertyChanged( - routing_id_, + Send(new ViewHostMsg_DevToolsRuntimePropertyChanged( + routing_id(), feature.utf8(), enabled ? "true" : "false")); } @@ -119,8 +113,8 @@ void DevToolsAgent::runtimeFeatureStateChanged( void DevToolsAgent::runtimePropertyChanged( const WebKit::WebString& name, const WebKit::WebString& value) { - render_view_->Send(new ViewHostMsg_DevToolsRuntimePropertyChanged( - routing_id_, + Send(new ViewHostMsg_DevToolsRuntimePropertyChanged( + routing_id(), name.utf8(), value.utf8())); } @@ -191,8 +185,15 @@ void DevToolsAgent::OnInspectElement(int x, int y) { } } +void DevToolsAgent::OnNavigate() { + WebDevToolsAgent* web_agent = GetWebAgent(); + if (web_agent) { + web_agent->didNavigate(); + } +} + WebDevToolsAgent* DevToolsAgent::GetWebAgent() { - WebView* web_view = render_view_->webview(); + WebView* web_view = render_view()->webview(); if (!web_view) return NULL; return web_view->devToolsAgent(); diff --git a/chrome/renderer/devtools_agent.h b/chrome/renderer/devtools_agent.h index 4b1b465..8f0f7f4 100644 --- a/chrome/renderer/devtools_agent.h +++ b/chrome/renderer/devtools_agent.h @@ -11,29 +11,34 @@ #include "base/basictypes.h" #include "chrome/common/devtools_messages.h" -#include "ipc/ipc_channel.h" +#include "chrome/renderer/render_view_observer.h" #include "third_party/WebKit/WebKit/chromium/public/WebDevToolsAgentClient.h" namespace WebKit { class WebDevToolsAgent; } -class RenderView; struct DevToolsMessageData; // DevToolsAgent belongs to the inspectable RenderView and provides Glue's // agents with the communication capabilities. All messages from/to Glue's -// agents infrastructure are flowing through this comminucation agent. +// agents infrastructure are flowing through this communication agent. // There is a corresponding DevToolsClient object on the client side. -class DevToolsAgent : public WebKit::WebDevToolsAgentClient, - public IPC::Channel::Listener { +class DevToolsAgent : public RenderViewObserver, + public WebKit::WebDevToolsAgentClient { public: - DevToolsAgent(int routing_id, RenderView* view); + explicit DevToolsAgent(RenderView* render_view); virtual ~DevToolsAgent(); - void OnNavigate(); + // Returns agent instance for its host id. + static DevToolsAgent* FromHostId(int host_id); + + WebKit::WebDevToolsAgent* GetWebAgent(); - // IPC::Channel::Listener implementation. + private: + friend class DevToolsAgentFilter; + + // RenderView::Observer implementation. virtual bool OnMessageReceived(const IPC::Message& message); // WebDevToolsAgentClient implementation @@ -50,26 +55,16 @@ class DevToolsAgent : public WebKit::WebDevToolsAgentClient, createClientMessageLoop(); virtual bool exposeV8DebuggerProtocol(); - // Returns agent instance for its host id. - static DevToolsAgent* FromHostId(int host_id); - - RenderView* render_view() { return render_view_; } - - WebKit::WebDevToolsAgent* GetWebAgent(); - - private: - friend class DevToolsAgentFilter; - void OnAttach(const DevToolsRuntimeProperties& runtime_properties); void OnDetach(); void OnFrontendLoaded(); void OnDispatchOnInspectorBackend(const std::string& message); void OnInspectElement(int x, int y); + void OnSetApuAgentEnabled(bool enabled); + void OnNavigate(); static std::map<int, DevToolsAgent*> agent_for_routing_id_; - int routing_id_; // View routing id that we can access from IO thread. - RenderView* render_view_; bool expose_v8_debugger_protocol_; DISALLOW_COPY_AND_ASSIGN(DevToolsAgent); diff --git a/chrome/renderer/devtools_client.cc b/chrome/renderer/devtools_client.cc index eea0b46..1f14035 100644 --- a/chrome/renderer/devtools_client.cc +++ b/chrome/renderer/devtools_client.cc @@ -18,12 +18,12 @@ using WebKit::WebDevToolsFrontend; using WebKit::WebString; -DevToolsClient::DevToolsClient(RenderView* view) - : render_view_(view) { +DevToolsClient::DevToolsClient(RenderView* render_view) + : RenderViewObserver(render_view) { const CommandLine& command_line = *CommandLine::ForCurrentProcess(); web_tools_frontend_.reset( WebDevToolsFrontend::create( - view->webview(), + render_view->webview(), this, ASCIIToUTF16(command_line.GetSwitchValueASCII(switches::kLang)))); } @@ -31,10 +31,9 @@ DevToolsClient::DevToolsClient(RenderView* view) DevToolsClient::~DevToolsClient() { } -void DevToolsClient::Send(const IPC::Message& tools_agent_message) { - render_view_->Send(new ViewHostMsg_ForwardToDevToolsAgent( - render_view_->routing_id(), - tools_agent_message)); +void DevToolsClient::SendToAgent(const IPC::Message& tools_agent_message) { + Send(new ViewHostMsg_ForwardToDevToolsAgent( + routing_id(), tools_agent_message)); } bool DevToolsClient::OnMessageReceived(const IPC::Message& message) { @@ -51,41 +50,36 @@ bool DevToolsClient::OnMessageReceived(const IPC::Message& message) { } void DevToolsClient::sendFrontendLoaded() { - Send(DevToolsAgentMsg_FrontendLoaded()); + SendToAgent(DevToolsAgentMsg_FrontendLoaded()); } void DevToolsClient::sendMessageToBackend(const WebString& message) { - Send(DevToolsAgentMsg_DispatchOnInspectorBackend(message.utf8())); + SendToAgent(DevToolsAgentMsg_DispatchOnInspectorBackend(message.utf8())); } void DevToolsClient::sendDebuggerCommandToAgent(const WebString& command) { - Send(DevToolsAgentMsg_DebuggerCommand(command.utf8())); + SendToAgent(DevToolsAgentMsg_DebuggerCommand(command.utf8())); } void DevToolsClient::activateWindow() { - render_view_->Send(new ViewHostMsg_ActivateDevToolsWindow( - render_view_->routing_id())); + Send(new ViewHostMsg_ActivateDevToolsWindow(routing_id())); } void DevToolsClient::closeWindow() { - render_view_->Send(new ViewHostMsg_CloseDevToolsWindow( - render_view_->routing_id())); + Send(new ViewHostMsg_CloseDevToolsWindow(routing_id())); } void DevToolsClient::requestDockWindow() { - render_view_->Send(new ViewHostMsg_RequestDockDevToolsWindow( - render_view_->routing_id())); + Send(new ViewHostMsg_RequestDockDevToolsWindow(routing_id())); } void DevToolsClient::requestUndockWindow() { - render_view_->Send(new ViewHostMsg_RequestUndockDevToolsWindow( - render_view_->routing_id())); + Send(new ViewHostMsg_RequestUndockDevToolsWindow(routing_id())); } -void DevToolsClient::OnDispatchOnInspectorFrontend( - const std::string& message) { - web_tools_frontend_->dispatchOnInspectorFrontend( - WebString::fromUTF8(message)); +void DevToolsClient::OnDispatchOnInspectorFrontend(const std::string& message) { + web_tools_frontend_->dispatchOnInspectorFrontend( + WebString::fromUTF8(message)); } bool DevToolsClient::shouldHideScriptsPanel() { diff --git a/chrome/renderer/devtools_client.h b/chrome/renderer/devtools_client.h index 463dc35..fbd7ccc 100644 --- a/chrome/renderer/devtools_client.h +++ b/chrome/renderer/devtools_client.h @@ -10,11 +10,10 @@ #include "base/basictypes.h" #include "base/scoped_ptr.h" -#include "ipc/ipc_channel.h" +#include "chrome/renderer/render_view_observer.h" #include "third_party/WebKit/WebKit/chromium/public/WebDevToolsFrontendClient.h" class MessageLoop; -class RenderView; namespace WebKit { class WebDevToolsFrontend; @@ -29,14 +28,15 @@ struct DevToolsMessageData; // corresponding DevToolsAgent object. // TODO(yurys): now the client is almost empty later it will delegate calls to // code in glue -class DevToolsClient : public WebKit::WebDevToolsFrontendClient, - public IPC::Channel::Listener { +class DevToolsClient : public RenderViewObserver, + public WebKit::WebDevToolsFrontendClient { public: - explicit DevToolsClient(RenderView* view); + explicit DevToolsClient(RenderView* render_view); virtual ~DevToolsClient(); - // IPC::Channel::Listener implementation. - bool OnMessageReceived(const IPC::Message& message); + private: + // RenderView::Observer implementation. + virtual bool OnMessageReceived(const IPC::Message& message); // WebDevToolsFrontendClient implementation virtual void sendFrontendLoaded(); @@ -50,13 +50,11 @@ class DevToolsClient : public WebKit::WebDevToolsFrontendClient, virtual bool shouldHideScriptsPanel(); - private: void OnDispatchOnInspectorFrontend(const std::string& message); // Sends message to DevToolsAgent. - void Send(const IPC::Message& tools_agent_message); + void SendToAgent(const IPC::Message& tools_agent_message); - RenderView* render_view_; // host render view scoped_ptr<WebKit::WebDevToolsFrontend> web_tools_frontend_; DISALLOW_COPY_AND_ASSIGN(DevToolsClient); diff --git a/chrome/renderer/geolocation_dispatcher.cc b/chrome/renderer/geolocation_dispatcher.cc index aefc346..c6aa51b 100644 --- a/chrome/renderer/geolocation_dispatcher.cc +++ b/chrome/renderer/geolocation_dispatcher.cc @@ -4,8 +4,7 @@ #include "chrome/renderer/geolocation_dispatcher.h" -#include "chrome/renderer/render_view.h" -#include "ipc/ipc_message.h" +#include "chrome/common/render_messages.h" #include "third_party/WebKit/WebKit/chromium/public/WebGeolocationPermissionRequest.h" #include "third_party/WebKit/WebKit/chromium/public/WebGeolocationPermissionRequestManager.h" #include "third_party/WebKit/WebKit/chromium/public/WebGeolocationClient.h" @@ -16,7 +15,7 @@ using namespace WebKit; GeolocationDispatcher::GeolocationDispatcher(RenderView* render_view) - : render_view_(render_view), + : RenderViewObserver(render_view), pending_permissions_(new WebGeolocationPermissionRequestManager()), enable_high_accuracy_(false), updating_(false) { @@ -43,14 +42,13 @@ void GeolocationDispatcher::geolocationDestroyed() { void GeolocationDispatcher::startUpdating() { GURL url; - render_view_->Send(new ViewHostMsg_Geolocation_StartUpdating( - render_view_->routing_id(), url, enable_high_accuracy_)); + Send(new ViewHostMsg_Geolocation_StartUpdating( + routing_id(), url, enable_high_accuracy_)); updating_ = true; } void GeolocationDispatcher::stopUpdating() { - render_view_->Send(new ViewHostMsg_Geolocation_StopUpdating( - render_view_->routing_id())); + Send(new ViewHostMsg_Geolocation_StopUpdating(routing_id())); updating_ = false; } @@ -85,8 +83,8 @@ void GeolocationDispatcher::requestPermission( const WebGeolocationPermissionRequest& permissionRequest) { int bridge_id = pending_permissions_->add(permissionRequest); string16 origin = permissionRequest.securityOrigin().toString(); - render_view_->Send(new ViewHostMsg_Geolocation_RequestPermission( - render_view_->routing_id(), bridge_id, GURL(origin))); + Send(new ViewHostMsg_Geolocation_RequestPermission( + routing_id(), bridge_id, GURL(origin))); } // TODO(jknotten): Change the messages to use a security origin, so no @@ -97,8 +95,8 @@ void GeolocationDispatcher::cancelPermissionRequest( if (!pending_permissions_->remove(permissionRequest, bridge_id)) return; string16 origin = permissionRequest.securityOrigin().toString(); - render_view_->Send(new ViewHostMsg_Geolocation_CancelPermissionRequest( - render_view_->routing_id(), bridge_id, GURL(origin))); + Send(new ViewHostMsg_Geolocation_CancelPermissionRequest( + routing_id(), bridge_id, GURL(origin))); } // Permission for using geolocation has been set. diff --git a/chrome/renderer/geolocation_dispatcher.h b/chrome/renderer/geolocation_dispatcher.h index 846e8e8..e9f3d41 100644 --- a/chrome/renderer/geolocation_dispatcher.h +++ b/chrome/renderer/geolocation_dispatcher.h @@ -7,10 +7,10 @@ #pragma once #include "base/scoped_ptr.h" +#include "chrome/renderer/render_view_observer.h" #include "third_party/WebKit/WebKit/chromium/public/WebGeolocationClient.h" #include "third_party/WebKit/WebKit/chromium/public/WebGeolocationController.h" -class RenderView; struct Geoposition; namespace WebKit { @@ -21,19 +21,17 @@ class WebGeolocationPosition; class WebSecurityOrigin; } -namespace IPC { -class Message; -} - // GeolocationDispatcher is a delegate for Geolocation messages used by // WebKit. // It's the complement of GeolocationDispatcherHost (owned by RenderViewHost). -class GeolocationDispatcher : public WebKit::WebGeolocationClient { +class GeolocationDispatcher : public RenderViewObserver, + public WebKit::WebGeolocationClient { public: explicit GeolocationDispatcher(RenderView* render_view); virtual ~GeolocationDispatcher(); - // IPC + private: + // RenderView::Observer implementation. bool OnMessageReceived(const IPC::Message& message); // WebGeolocationClient @@ -48,7 +46,6 @@ class GeolocationDispatcher : public WebKit::WebGeolocationClient { virtual void cancelPermissionRequest( const WebKit::WebGeolocationPermissionRequest& permissionRequest); - private: // Permission for using geolocation has been set. void OnGeolocationPermissionSet(int bridge_id, bool is_allowed); diff --git a/chrome/renderer/notification_provider.cc b/chrome/renderer/notification_provider.cc index 0196d0c..e5e87f9 100644 --- a/chrome/renderer/notification_provider.cc +++ b/chrome/renderer/notification_provider.cc @@ -25,8 +25,8 @@ using WebKit::WebSecurityOrigin; using WebKit::WebString; using WebKit::WebURL; -NotificationProvider::NotificationProvider(RenderView* view) - : view_(view) { +NotificationProvider::NotificationProvider(RenderView* render_view) + : RenderViewObserver(render_view) { } NotificationProvider::~NotificationProvider() { @@ -46,7 +46,7 @@ void NotificationProvider::cancel(const WebNotification& notification) { bool id_found = manager_.GetId(notification, id); // Won't be found if the notification has already been closed by the user. if (id_found) - Send(new ViewHostMsg_CancelDesktopNotification(view_->routing_id(), id)); + Send(new ViewHostMsg_CancelDesktopNotification(routing_id(), id)); } void NotificationProvider::objectDestroyed( @@ -62,7 +62,7 @@ WebNotificationPresenter::Permission NotificationProvider::checkPermission( const WebURL& url) { int permission; Send(new ViewHostMsg_CheckNotificationPermission( - view_->routing_id(), + routing_id(), url, &permission)); return static_cast<WebNotificationPresenter::Permission>(permission); @@ -72,12 +72,12 @@ void NotificationProvider::requestPermission( const WebSecurityOrigin& origin, WebNotificationPermissionCallback* callback) { // We only request permission in response to a user gesture. - if (!view_->webview()->mainFrame()->isProcessingUserGesture()) + if (!render_view()->webview()->mainFrame()->isProcessingUserGesture()) return; int id = manager_.RegisterPermissionRequest(callback); - Send(new ViewHostMsg_RequestNotificationPermission(view_->routing_id(), + Send(new ViewHostMsg_RequestNotificationPermission(routing_id(), GURL(origin.toString()), id)); } @@ -93,11 +93,11 @@ bool NotificationProvider::OnMessageReceived(const IPC::Message& message) { OnPermissionRequestComplete); IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() - return handled; -} -void NotificationProvider::OnNavigate() { - manager_.Clear(); + if (message.type() == ViewMsg_Navigate::ID) + OnNavigate(); // Don't want to swallow the message. + + return handled; } bool NotificationProvider::ShowHTML(const WebNotification& notification, @@ -113,13 +113,13 @@ bool NotificationProvider::ShowHTML(const WebNotification& notification, DCHECK(notification.isHTML()); ViewHostMsg_ShowNotification_Params params; - params.origin = GURL(view_->webview()->mainFrame()->url()).GetOrigin(); + params.origin = + GURL(render_view()->webview()->mainFrame()->url()).GetOrigin(); params.is_html = true; params.contents_url = notification.url(); params.notification_id = id; params.replace_id = notification.replaceId(); - return Send(new ViewHostMsg_ShowDesktopNotification(view_->routing_id(), - params)); + return Send(new ViewHostMsg_ShowDesktopNotification(routing_id(), params)); } bool NotificationProvider::ShowText(const WebNotification& notification, @@ -127,7 +127,8 @@ bool NotificationProvider::ShowText(const WebNotification& notification, DCHECK(!notification.isHTML()); ViewHostMsg_ShowNotification_Params params; params.is_html = false; - params.origin = GURL(view_->webview()->mainFrame()->url()).GetOrigin(); + params.origin = GURL( + render_view()->webview()->mainFrame()->url()).GetOrigin(); params.icon_url = notification.iconURL(); params.title = notification.title(); params.body = notification.body(); @@ -135,8 +136,7 @@ bool NotificationProvider::ShowText(const WebNotification& notification, params.notification_id = id; params.replace_id = notification.replaceId(); - return Send(new ViewHostMsg_ShowDesktopNotification(view_->routing_id(), - params)); + return Send(new ViewHostMsg_ShowDesktopNotification(routing_id(), params)); } void NotificationProvider::OnDisplay(int id) { @@ -184,6 +184,6 @@ void NotificationProvider::OnPermissionRequestComplete(int id) { manager_.OnPermissionRequestComplete(id); } -bool NotificationProvider::Send(IPC::Message* message) { - return RenderThread::current()->Send(message); +void NotificationProvider::OnNavigate() { + manager_.Clear(); } diff --git a/chrome/renderer/notification_provider.h b/chrome/renderer/notification_provider.h index 1ba84b2..85cccff 100644 --- a/chrome/renderer/notification_provider.h +++ b/chrome/renderer/notification_provider.h @@ -7,23 +7,26 @@ #pragma once #include "chrome/common/desktop_notifications/active_notification_tracker.h" -#include "ipc/ipc_channel.h" +#include "chrome/renderer/render_view_observer.h" #include "third_party/WebKit/WebKit/chromium/public/WebNotification.h" #include "third_party/WebKit/WebKit/chromium/public/WebNotificationPresenter.h" -class RenderView; namespace WebKit { class WebNotificationPermissionCallback; } // NotificationProvider class is owned by the RenderView. Only -// to be used on the UI thread. -class NotificationProvider : public WebKit::WebNotificationPresenter, - public IPC::Channel::Listener { +// to be used on the main thread. +class NotificationProvider : public RenderViewObserver, + public WebKit::WebNotificationPresenter { public: - explicit NotificationProvider(RenderView* view); + explicit NotificationProvider(RenderView* render_view); virtual ~NotificationProvider(); + private: + // RenderView::Observer implementation. + bool OnMessageReceived(const IPC::Message& message); + // WebKit::WebNotificationPresenter interface. virtual bool show(const WebKit::WebNotification& proxy); virtual void cancel(const WebKit::WebNotification& proxy); @@ -33,13 +36,6 @@ class NotificationProvider : public WebKit::WebNotificationPresenter, virtual void requestPermission(const WebKit::WebSecurityOrigin& origin, WebKit::WebNotificationPermissionCallback* callback); - // IPC::Channel::Listener implementation. - bool OnMessageReceived(const IPC::Message& message); - - // Called when the RenderView navigates. - void OnNavigate(); - - private: // Internal methods used to show notifications. bool ShowHTML(const WebKit::WebNotification& notification, int id); bool ShowText(const WebKit::WebNotification& notification, int id); @@ -50,12 +46,7 @@ class NotificationProvider : public WebKit::WebNotificationPresenter, void OnClose(int id, bool by_user); void OnClick(int id); void OnPermissionRequestComplete(int id); - - bool Send(IPC::Message* message); - - // Non-owned pointer to the RenderView object which created and owns - // this object. - RenderView* view_; + void OnNavigate(); // A tracker object which manages the active notifications and the IDs // that are used to refer to them over IPC. diff --git a/chrome/renderer/page_click_tracker.cc b/chrome/renderer/page_click_tracker.cc index c974808..c11494e 100644 --- a/chrome/renderer/page_click_tracker.cc +++ b/chrome/renderer/page_click_tracker.cc @@ -26,12 +26,12 @@ using WebKit::WebString; using WebKit::WebView; PageClickTracker::PageClickTracker(RenderView* render_view) - : render_view_(render_view), + : RenderViewObserver(render_view), was_focused_(false) { } PageClickTracker::~PageClickTracker() { - // Note that even though RenderView calls StopTrackingFrame when notified that + // Note that even though RenderView calls FrameDetached when notified that // a frame was closed, it might not always get that notification from WebKit // for all frames. // By the time we get here, the frame could have been destroyed so we cannot @@ -39,27 +39,6 @@ PageClickTracker::~PageClickTracker() { // be invalid. } -void PageClickTracker::StartTrackingFrame(WebFrame* frame) { - tracked_frames_.push_back(frame); - frame->document().addEventListener("mousedown", this, false); -} - -void PageClickTracker::StopTrackingFrame(WebFrame* frame, bool frame_detached) { - FrameList::iterator iter = - std::find(tracked_frames_.begin(), tracked_frames_.end(), frame); - if (iter == tracked_frames_.end()) { - // Some frames might never load contents so we may not have a listener on - // them. Calling removeEventListener() on them would trigger an assert, so - // we need to keep track of which frames we are listening to. - return; - } - tracked_frames_.erase(iter); - // If the frame has been detached, all event listeners have already been - // removed. - if (!frame_detached) - frame->document().removeEventListener("mousedown", this, false); -} - void PageClickTracker::DidHandleMouseEvent(const WebMouseEvent& event) { if (event.type != WebInputEvent::MouseDown || last_node_clicked_.isNull()) { @@ -98,6 +77,38 @@ void PageClickTracker::RemoveListener(PageClickListener* listener) { listeners_.RemoveObserver(listener); } +bool PageClickTracker::OnMessageReceived(const IPC::Message& message) { + if (message.type() == ViewMsg_HandleInputEvent::ID) { + void* iter = NULL; + const char* data; + int data_length; + if (message.ReadData(&iter, &data, &data_length)) { + const WebInputEvent* input_event = + reinterpret_cast<const WebInputEvent*>(data); + if (WebInputEvent::isMouseEventType(input_event->type)) + DidHandleMouseEvent(*(static_cast<const WebMouseEvent*>(input_event))); + } + } + return false; +} + +void PageClickTracker::DidFinishDocumentLoad(WebKit::WebFrame* frame) { + tracked_frames_.push_back(frame); + frame->document().addEventListener("mousedown", this, false); +} + +void PageClickTracker::FrameDetached(WebKit::WebFrame* frame) { + FrameList::iterator iter = + std::find(tracked_frames_.begin(), tracked_frames_.end(), frame); + if (iter == tracked_frames_.end()) { + // Some frames might never load contents so we may not have a listener on + // them. Calling removeEventListener() on them would trigger an assert, so + // we need to keep track of which frames we are listening to. + return; + } + tracked_frames_.erase(iter); +} + void PageClickTracker::handleEvent(const WebDOMEvent& event) { last_node_clicked_.reset(); @@ -117,7 +128,7 @@ void PageClickTracker::handleEvent(const WebDOMEvent& event) { } WebNode PageClickTracker::GetFocusedNode() { - WebView* web_view = render_view_->webview(); + WebView* web_view = render_view()->webview(); if (!web_view) return WebNode(); diff --git a/chrome/renderer/page_click_tracker.h b/chrome/renderer/page_click_tracker.h index 492237c..d765310 100644 --- a/chrome/renderer/page_click_tracker.h +++ b/chrome/renderer/page_click_tracker.h @@ -9,17 +9,12 @@ #include "base/basictypes.h" #include "base/observer_list.h" +#include "chrome/renderer/render_view_observer.h" #include "third_party/WebKit/WebKit/chromium/public/WebDOMEventListener.h" #include "third_party/WebKit/WebKit/chromium/public/WebNode.h" class PageClickListener; -class RenderView; -namespace WebKit { -class WebFrame; -class WebDOMEvent; -class WebMouseEvent; -} // This class is responsible for tracking clicks on elements in web pages and // notifiying the associated listener when a node is clicked. @@ -33,23 +28,12 @@ class WebMouseEvent; // could easily be changed to report click on any type of WebNode. // // There is one PageClickTracker per RenderView. - -class PageClickTracker : public WebKit::WebDOMEventListener { +class PageClickTracker : public RenderViewObserver, + public WebKit::WebDOMEventListener { public: explicit PageClickTracker(RenderView* render_view); virtual ~PageClickTracker(); - // Starts reporting node clicks for |frame| on the listener previously - // specified with SetListener(). - void StartTrackingFrame(WebKit::WebFrame* frame); - - // Stops reporting node clicks for |frame|. |frame_detached| should be true - // if the frame has already been detached. - void StopTrackingFrame(WebKit::WebFrame* frame, bool frame_detached); - - // Called after the mouse event |event| has been processed by WebKit. - void DidHandleMouseEvent(const WebKit::WebMouseEvent& event); - // Adds/removes a listener for getting notification when an element is // clicked. Note that the order of insertion is important as a listener when // notified can decide to stop the propagation of the event (so that listeners @@ -58,9 +42,17 @@ class PageClickTracker : public WebKit::WebDOMEventListener { void RemoveListener(PageClickListener* listener); private: + // RenderView::Observer implementation. + virtual bool OnMessageReceived(const IPC::Message& message); + virtual void DidFinishDocumentLoad(WebKit::WebFrame* frame); + virtual void FrameDetached(WebKit::WebFrame* frame); + // WebKit::WebDOMEventListener implementation. virtual void handleEvent(const WebKit::WebDOMEvent& event); + // Called after the mouse event |event| has been processed by WebKit. + void DidHandleMouseEvent(const WebKit::WebMouseEvent& event); + // Returns the currently focused node in the associated render view. // That node may be null. WebKit::WebNode GetFocusedNode(); @@ -68,9 +60,6 @@ class PageClickTracker : public WebKit::WebDOMEventListener { // The last node that was clicked and had focus. WebKit::WebNode last_node_clicked_; - // The render view we are associated with. - RenderView* render_view_; - // Whether the last clicked node had focused before it was clicked. bool was_focused_; diff --git a/chrome/renderer/page_click_tracker_unittest.cc b/chrome/renderer/page_click_tracker_unittest.cc index dcba0bb..fcb4463 100644 --- a/chrome/renderer/page_click_tracker_unittest.cc +++ b/chrome/renderer/page_click_tracker_unittest.cc @@ -49,10 +49,14 @@ class TestPageClickListener : public PageClickListener { // Tests that PageClickTracker does notify correctly when a node is clicked. TEST_F(RenderViewTest, PageClickTracker) { + // RenderView creates PageClickTracker but it doesn't keep it around. Rather + // than make it do so for the test, we create a new object. + PageClickTracker* page_click_tracker = new PageClickTracker(view_); + TestPageClickListener test_listener1; TestPageClickListener test_listener2; - view_->page_click_tracker()->AddListener(&test_listener1); - view_->page_click_tracker()->AddListener(&test_listener2); + page_click_tracker->AddListener(&test_listener1); + page_click_tracker->AddListener(&test_listener2); LoadHTML("<form>" " <input type='text' id='text'></input><br>" @@ -106,14 +110,14 @@ TEST_F(RenderViewTest, PageClickTracker) { test_listener1.ClearResults(); // Make sure removing a listener work. - view_->page_click_tracker()->RemoveListener(&test_listener1); + page_click_tracker->RemoveListener(&test_listener1); EXPECT_TRUE(SimulateElementClick("text")); EXPECT_FALSE(test_listener1.called_); EXPECT_TRUE(test_listener2.called_); test_listener2.ClearResults(); // Make sure we don't choke when no listeners are registered. - view_->page_click_tracker()->RemoveListener(&test_listener2); + page_click_tracker->RemoveListener(&test_listener2); EXPECT_TRUE(SimulateElementClick("text")); EXPECT_FALSE(test_listener1.called_); EXPECT_FALSE(test_listener2.called_); diff --git a/chrome/renderer/password_autocomplete_manager.cc b/chrome/renderer/password_autocomplete_manager.cc index 2c59b7d..ac1a90c 100644 --- a/chrome/renderer/password_autocomplete_manager.cc +++ b/chrome/renderer/password_autocomplete_manager.cc @@ -171,47 +171,13 @@ bool DoUsernamesMatch(const string16& username1, PasswordAutocompleteManager::PasswordAutocompleteManager( RenderView* render_view) - : render_view_(render_view), + : RenderViewObserver(render_view), ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { } PasswordAutocompleteManager::~PasswordAutocompleteManager() { } -void PasswordAutocompleteManager::ReceivedPasswordFormFillData( - WebKit::WebView* view, - const webkit_glue::PasswordFormFillData& form_data) { - FormElementsList forms; - // We own the FormElements* in forms. - FindFormElements(view, form_data.basic_data, &forms); - FormElementsList::iterator iter; - for (iter = forms.begin(); iter != forms.end(); ++iter) { - scoped_ptr<FormElements> form_elements(*iter); - - // If wait_for_username is true, we don't want to initially fill the form - // until the user types in a valid username. - if (!form_data.wait_for_username) - FillForm(form_elements.get(), form_data.basic_data); - - // Attach autocomplete listener to enable selecting alternate logins. - // First, get pointers to username element. - WebKit::WebInputElement username_element = - form_elements->input_elements[form_data.basic_data.fields[0].name()]; - - // Get pointer to password element. (We currently only support single - // password forms). - WebKit::WebInputElement password_element = - form_elements->input_elements[form_data.basic_data.fields[1].name()]; - - DCHECK(login_to_password_info_.find(username_element) == - login_to_password_info_.end()); - PasswordInfo password_info; - password_info.fill_data = form_data; - password_info.password_field = password_element; - login_to_password_info_[username_element] = password_info; - } -} - void PasswordAutocompleteManager::FrameClosing(const WebKit::WebFrame* frame) { for (LoginToPasswordInfoMap::iterator iter = login_to_password_info_.begin(); iter != login_to_password_info_.end();) { @@ -376,14 +342,31 @@ void PasswordAutocompleteManager::SendPasswordForms(WebKit::WebFrame* frame, return; if (only_visible) { - render_view_->Send( - new ViewHostMsg_PasswordFormsVisible(GetRoutingID(), password_forms)); + Send(new ViewHostMsg_PasswordFormsVisible(routing_id(), password_forms)); } else { - render_view_->Send( - new ViewHostMsg_PasswordFormsFound(GetRoutingID(), password_forms)); + Send(new ViewHostMsg_PasswordFormsFound(routing_id(), password_forms)); } } +bool PasswordAutocompleteManager::OnMessageReceived( + const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PasswordAutocompleteManager, message) + IPC_MESSAGE_HANDLER(ViewMsg_FillPasswordForm, OnFillPasswordForm) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PasswordAutocompleteManager::DidFinishDocumentLoad( + WebKit::WebFrame* frame) { + SendPasswordForms(frame, false); +} + +void PasswordAutocompleteManager::DidFinishLoad(WebKit::WebFrame* frame) { + SendPasswordForms(frame, true); +} + //////////////////////////////////////////////////////////////////////////////// // PageClickListener implementation: @@ -395,6 +378,39 @@ bool PasswordAutocompleteManager::InputElementClicked( return false; } +void PasswordAutocompleteManager::OnFillPasswordForm( + const webkit_glue::PasswordFormFillData& form_data) { + FormElementsList forms; + // We own the FormElements* in forms. + FindFormElements(render_view()->webview(), form_data.basic_data, &forms); + FormElementsList::iterator iter; + for (iter = forms.begin(); iter != forms.end(); ++iter) { + scoped_ptr<FormElements> form_elements(*iter); + + // If wait_for_username is true, we don't want to initially fill the form + // until the user types in a valid username. + if (!form_data.wait_for_username) + FillForm(form_elements.get(), form_data.basic_data); + + // Attach autocomplete listener to enable selecting alternate logins. + // First, get pointers to username element. + WebKit::WebInputElement username_element = + form_elements->input_elements[form_data.basic_data.fields[0].name()]; + + // Get pointer to password element. (We currently only support single + // password forms). + WebKit::WebInputElement password_element = + form_elements->input_elements[form_data.basic_data.fields[1].name()]; + + DCHECK(login_to_password_info_.find(username_element) == + login_to_password_info_.end()); + PasswordInfo password_info; + password_info.fill_data = form_data; + password_info.password_field = password_element; + login_to_password_info_[username_element] = password_info; + } +} + //////////////////////////////////////////////////////////////////////////////// // PasswordAutocompleteManager, private: @@ -481,7 +497,3 @@ bool PasswordAutocompleteManager::FillUserNameAndPassword( SetElementAutofilled(password_element, true); return true; } - -int PasswordAutocompleteManager::GetRoutingID() const { - return render_view_->routing_id(); -} diff --git a/chrome/renderer/password_autocomplete_manager.h b/chrome/renderer/password_autocomplete_manager.h index c4e4b2f..f2aa112 100644 --- a/chrome/renderer/password_autocomplete_manager.h +++ b/chrome/renderer/password_autocomplete_manager.h @@ -11,28 +11,23 @@ #include "base/task.h" #include "chrome/renderer/page_click_listener.h" +#include "chrome/renderer/render_view_observer.h" #include "webkit/glue/password_form_dom_manager.h" #include "third_party/WebKit/WebKit/chromium/public/WebInputElement.h" -class RenderView; namespace WebKit { +class WebInputElement; class WebKeyboardEvent; -class WebView; } // This class is responsible for filling password forms. // There is one PasswordAutocompleteManager per RenderView. -class PasswordAutocompleteManager : public PageClickListener { +class PasswordAutocompleteManager : public RenderViewObserver, + public PageClickListener { public: explicit PasswordAutocompleteManager(RenderView* render_view); virtual ~PasswordAutocompleteManager(); - // Invoked by the renderer when it receives the password info from the - // browser. This triggers a password autocomplete (if wait_for_username is - // false on |form_data|). - void ReceivedPasswordFormFillData(WebKit::WebView* view, - const webkit_glue::PasswordFormFillData& form_data); - // Invoked when the passed frame is closing. Gives us a chance to clear any // reference we may have to elements in that frame. void FrameClosing(const WebKit::WebFrame* frame); @@ -50,10 +45,6 @@ class PasswordAutocompleteManager : public PageClickListener { const WebKit::WebInputElement& password, const webkit_glue::PasswordFormFillData& fill_data); - // Scans the given frame for password forms and sends them up to the browser. - // If |only_visible| is true, only forms visible in the layout are sent. - void SendPasswordForms(WebKit::WebFrame* frame, bool only_visible); - // WebViewClient editor related calls forwarded by the RenderView. // If they return true, it indicates the event was consumed and should not // be used for any other autofill activity. @@ -63,6 +54,8 @@ class PasswordAutocompleteManager : public PageClickListener { const WebKit::WebKeyboardEvent& event); private: + friend class PasswordAutocompleteManagerTest; + struct PasswordInfo { WebKit::WebInputElement password_field; webkit_glue::PasswordFormFillData fill_data; @@ -71,11 +64,23 @@ class PasswordAutocompleteManager : public PageClickListener { }; typedef std::map<WebKit::WebElement, PasswordInfo> LoginToPasswordInfoMap; + // RenderView::Observer implementation. + virtual bool OnMessageReceived(const IPC::Message& message); + virtual void DidFinishDocumentLoad(WebKit::WebFrame* frame); + virtual void DidFinishLoad(WebKit::WebFrame* frame); + // PageClickListener implementation: virtual bool InputElementClicked(const WebKit::WebInputElement& element, bool was_focused, bool is_focused); + void OnFillPasswordForm( + const webkit_glue::PasswordFormFillData& form_data); + + // Scans the given frame for password forms and sends them up to the browser. + // If |only_visible| is true, only forms visible in the layout are sent. + void SendPasswordForms(WebKit::WebFrame* frame, bool only_visible); + void GetSuggestions( const webkit_glue::PasswordFormFillData& fill_data, const string16& input, @@ -92,13 +97,6 @@ class PasswordAutocompleteManager : public PageClickListener { bool exact_username_match, bool set_selection); - // Convenience method that returns the routing ID of the render view we are - // associated with. - int GetRoutingID() const; - - // Weak reference. - RenderView* render_view_; - // The logins we have filled so far with their associated info. LoginToPasswordInfoMap login_to_password_info_; diff --git a/chrome/renderer/password_autocomplete_manager_unittest.cc b/chrome/renderer/password_autocomplete_manager_unittest.cc index fd6546f..7f378b96 100644 --- a/chrome/renderer/password_autocomplete_manager_unittest.cc +++ b/chrome/renderer/password_autocomplete_manager_unittest.cc @@ -4,6 +4,7 @@ #include "base/string_util.h" #include "base/utf_string_conversions.h" +#include "chrome/renderer/autofill_helper.h" #include "chrome/renderer/password_autocomplete_manager.h" #include "chrome/test/render_view_test.h" #include "testing/gtest/include/gtest/gtest.h" @@ -62,7 +63,7 @@ class PasswordAutocompleteManagerTest : public RenderViewTest { void SimulateOnFillPasswordForm( const PasswordFormFillData& fill_data) { ViewMsg_FillPasswordForm msg(0, fill_data); - view_->OnMessageReceived(msg); + password_autocomplete_->OnMessageReceived(msg); } virtual void SetUp() { @@ -117,7 +118,7 @@ class PasswordAutocompleteManagerTest : public RenderViewTest { username_element_.setValue(WebString::fromUTF8(username)); if (move_caret_to_end) username_element_.setSelectionRange(username.length(), username.length()); - view_->textFieldDidChange(username_element_); + autofill_helper_->textFieldDidChange(username_element_); // Processing is delayed because of a WebKit bug, see // PasswordAutocompleteManager::TextDidChangeInTextField() for details. MessageLoop::current()->RunAllPending(); @@ -127,7 +128,7 @@ class PasswordAutocompleteManagerTest : public RenderViewTest { ui::KeyboardCode key_code) { WebKit::WebKeyboardEvent key_event; key_event.windowsKeyCode = key_code; - view_->textFieldDidReceiveKeyDown(element, key_event); + autofill_helper_->textFieldDidReceiveKeyDown(element, key_event); } void CheckTextFieldsState(const std::string& username, @@ -243,16 +244,16 @@ TEST_F(PasswordAutocompleteManagerTest, WaitUsername) { // Autocomplete should happen only when the username textfield is blurred with // a full match. username_element_.setValue("a"); - view_->textFieldDidEndEditing(username_element_); + autofill_helper_->textFieldDidEndEditing(username_element_); CheckTextFieldsState("a", false, "", false); username_element_.setValue("al"); - view_->textFieldDidEndEditing(username_element_); + autofill_helper_->textFieldDidEndEditing(username_element_); CheckTextFieldsState("al", false, "", false); username_element_.setValue("alices"); - view_->textFieldDidEndEditing(username_element_); + autofill_helper_->textFieldDidEndEditing(username_element_); CheckTextFieldsState("alices", false, "", false); username_element_.setValue(ASCIIToUTF16(kAliceUsername)); - view_->textFieldDidEndEditing(username_element_); + autofill_helper_->textFieldDidEndEditing(username_element_); CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true); } @@ -326,7 +327,7 @@ TEST_F(PasswordAutocompleteManagerTest, SuggestionSelect) { // WebView does: it sets the element value then calls // didAcceptAutocompleteSuggestion on the renderer. username_element_.setValue(ASCIIToUTF16(kAliceUsername)); - view_->didAcceptAutocompleteSuggestion(username_element_); + autofill_helper_->didAcceptAutocompleteSuggestion(username_element_); // Autocomplete should have kicked in. CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true); diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index 19fd677..a2ca602 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -78,6 +78,7 @@ #include "chrome/renderer/print_web_view_helper.h" #include "chrome/renderer/render_process.h" #include "chrome/renderer/render_thread.h" +#include "chrome/renderer/render_view_observer.h" #include "chrome/renderer/render_view_visitor.h" #include "chrome/renderer/render_widget_fullscreen.h" #include "chrome/renderer/render_widget_fullscreen_pepper.h" @@ -520,10 +521,16 @@ struct RenderView::PendingFileChooser { }; RenderView::RenderView(RenderThreadBase* render_thread, - const WebPreferences& webkit_preferences, - int64 session_storage_namespace_id) + gfx::NativeViewId parent_hwnd, + int32 opener_id, + const RendererPreferences& renderer_prefs, + const WebPreferences& webkit_prefs, + SharedRenderViewCounter* counter, + int32 routing_id, + int64 session_storage_namespace_id, + const string16& frame_name) : RenderWidget(render_thread, WebKit::WebPopupTypeNone), - webkit_preferences_(webkit_preferences), + webkit_preferences_(webkit_prefs), send_content_state_immediately_(false), enabled_bindings_(0), send_preferred_size_changes_(false), @@ -548,16 +555,16 @@ RenderView::RenderView(RenderThreadBase* render_thread, browser_window_id_(-1), ALLOW_THIS_IN_INITIALIZER_LIST(pepper_delegate_(this)), ALLOW_THIS_IN_INITIALIZER_LIST(page_info_method_factory_(this)), - ALLOW_THIS_IN_INITIALIZER_LIST(autofill_method_factory_(this)), ALLOW_THIS_IN_INITIALIZER_LIST(accessibility_method_factory_(this)), ALLOW_THIS_IN_INITIALIZER_LIST(translate_helper_(this)), ALLOW_THIS_IN_INITIALIZER_LIST(cookie_jar_(this)), - ALLOW_THIS_IN_INITIALIZER_LIST( - notification_provider_(new NotificationProvider(this))), + devtools_client_(NULL), + geolocation_dispatcher_(NULL), + speech_input_dispatcher_(NULL), + device_orientation_dispatcher_(NULL), accessibility_ack_pending_(false), pending_app_icon_requests_(0), session_storage_namespace_id_(session_storage_namespace_id), - decrement_shared_popup_at_destruction_(false), custom_menu_listener_(NULL) { #if defined(OS_MACOSX) // On Mac, the select popups are rendered by the browser. @@ -565,14 +572,7 @@ RenderView::RenderView(RenderThreadBase* render_thread, // in single-process mode. WebKit::WebView::setUseExternalPopupMenus(true); #endif - password_autocomplete_manager_.reset(new PasswordAutocompleteManager(this)); - autofill_helper_.reset(new AutoFillHelper(this)); - page_click_tracker_.reset(new PageClickTracker(this)); - // Note that the order of insertion of the listeners is important. - // The password_autocomplete_manager_ takes the first shot at processing the - // notification and can stop the propagation. - page_click_tracker_->AddListener(password_autocomplete_manager_.get()); - page_click_tracker_->AddListener(autofill_helper_.get()); + ClearBlockedContentSettings(); if (CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnableClientSidePhishingDetection)) { @@ -583,6 +583,66 @@ RenderView::RenderView(RenderThreadBase* render_thread, phishing_delegate_->SetPhishingScorer(thread->phishing_scorer()); } } + + routing_id_ = routing_id; + if (opener_id != MSG_ROUTING_NONE) + opener_id_ = opener_id; + + if (counter) { + shared_popup_counter_ = counter; + shared_popup_counter_->data++; + decrement_shared_popup_at_destruction_ = true; + } else { + shared_popup_counter_ = new SharedRenderViewCounter(0); + decrement_shared_popup_at_destruction_ = false; + } + + notification_provider_ = new NotificationProvider(this); + + devtools_agent_ = new DevToolsAgent(this); + PasswordAutocompleteManager* password_autocomplete_manager = + new PasswordAutocompleteManager(this); + AutoFillHelper* autofill_helper = new AutoFillHelper( + this, password_autocomplete_manager); + + webwidget_ = WebView::create(this, devtools_agent_, autofill_helper); + g_view_map.Get().insert(std::make_pair(webview(), this)); + webkit_preferences_.Apply(webview()); + webview()->initializeMainFrame(this); + if (!frame_name.empty()) + webview()->mainFrame()->setName(frame_name); + + OnSetRendererPrefs(renderer_prefs); + + render_thread_->AddRoute(routing_id_, this); + // Take a reference on behalf of the RenderThread. This will be balanced + // when we receive ViewMsg_Close. + AddRef(); + + // If this is a popup, we must wait for the CreatingNew_ACK message before + // completing initialization. Otherwise, we can finish it now. + if (opener_id == MSG_ROUTING_NONE) { + did_show_ = true; + CompleteInit(parent_hwnd); + } + + host_window_ = parent_hwnd; + + const CommandLine& command_line = *CommandLine::ForCurrentProcess(); + if (command_line.HasSwitch(switches::kDomAutomationController)) + enabled_bindings_ |= BindingsPolicy::DOM_AUTOMATION; + if (command_line.HasSwitch(switches::kEnableAccessibility)) + WebAccessibilityCache::enableAccessibility(); + + audio_message_filter_ = new AudioMessageFilter(routing_id_); + render_thread_->AddFilter(audio_message_filter_); + + PageClickTracker* page_click_tracker = new PageClickTracker(this); + // Note that the order of insertion of the listeners is important. + // The password_autocomplete_manager takes the first shot at processing the + // notification and can stop the propagation. + page_click_tracker->AddListener(password_autocomplete_manager); + page_click_tracker->AddListener(autofill_helper); } RenderView::~RenderView() { @@ -624,6 +684,9 @@ RenderView::~RenderView() { for (ViewMap::iterator it = views->begin(); it != views->end(); ++it) DCHECK_NE(this, it->second) << "Failed to call Close?"; #endif + + FOR_EACH_OBSERVER(RenderViewObserver, observers_, set_render_view(NULL)); + FOR_EACH_OBSERVER(RenderViewObserver, observers_, OnDestruct()); } /*static*/ @@ -654,15 +717,16 @@ RenderView* RenderView::Create( int64 session_storage_namespace_id, const string16& frame_name) { DCHECK(routing_id != MSG_ROUTING_NONE); - scoped_refptr<RenderView> view(new RenderView(render_thread, webkit_prefs, - session_storage_namespace_id)); - view->Init(parent_hwnd, - opener_id, - renderer_prefs, - counter, - routing_id, - frame_name); // adds reference - return view; + return new RenderView( + render_thread, + parent_hwnd, + opener_id, + renderer_prefs, + webkit_prefs, + counter, + routing_id, + session_storage_namespace_id, + frame_name); // adds reference } // static @@ -674,6 +738,15 @@ void RenderView::SetNextPageID(int32 next_page_id) { next_page_id_ = next_page_id; } +void RenderView::AddObserver(RenderViewObserver* observer) { + observers_.AddObserver(observer); +} + +void RenderView::RemoveObserver(RenderViewObserver* observer) { + observer->set_render_view(NULL); + observers_.RemoveObserver(observer); +} + bool RenderView::RendererAccessibilityNotification::ShouldIncludeChildren() { typedef ViewHostMsg_AccessibilityNotification_Params params; if (type == params::NOTIFICATION_TYPE_CHILDREN_CHANGED || @@ -894,86 +967,16 @@ void RenderView::UnregisterBlockedPlugin(BlockedPlugin* blocked_plugin) { blocked_plugins_.erase(blocked_plugin); } -void RenderView::Init(gfx::NativeViewId parent_hwnd, - int32 opener_id, - const RendererPreferences& renderer_prefs, - SharedRenderViewCounter* counter, - int32 routing_id, - const string16& frame_name) { - DCHECK(!webview()); - - if (opener_id != MSG_ROUTING_NONE) - opener_id_ = opener_id; - - if (counter) { - shared_popup_counter_ = counter; - shared_popup_counter_->data++; - decrement_shared_popup_at_destruction_ = true; - } else { - shared_popup_counter_ = new SharedRenderViewCounter(0); - decrement_shared_popup_at_destruction_ = false; - } - - devtools_agent_.reset(new DevToolsAgent(routing_id, this)); - - webwidget_ = WebView::create(this, devtools_agent_.get(), this); - g_view_map.Get().insert(std::make_pair(webview(), this)); - webkit_preferences_.Apply(webview()); - webview()->initializeMainFrame(this); - if (!frame_name.empty()) - webview()->mainFrame()->setName(frame_name); - - OnSetRendererPrefs(renderer_prefs); - - routing_id_ = routing_id; - render_thread_->AddRoute(routing_id_, this); - // Take a reference on behalf of the RenderThread. This will be balanced - // when we receive ViewMsg_Close. - AddRef(); - - // If this is a popup, we must wait for the CreatingNew_ACK message before - // completing initialization. Otherwise, we can finish it now. - if (opener_id == MSG_ROUTING_NONE) { - did_show_ = true; - CompleteInit(parent_hwnd); - } - - host_window_ = parent_hwnd; - - const CommandLine& command_line = *CommandLine::ForCurrentProcess(); - if (command_line.HasSwitch(switches::kDomAutomationController)) - enabled_bindings_ |= BindingsPolicy::DOM_AUTOMATION; - if (command_line.HasSwitch(switches::kEnableAccessibility)) - WebAccessibilityCache::enableAccessibility(); - - audio_message_filter_ = new AudioMessageFilter(routing_id_); - render_thread_->AddFilter(audio_message_filter_); -} - bool RenderView::OnMessageReceived(const IPC::Message& message) { WebFrame* main_frame = webview() ? webview()->mainFrame() : NULL; if (main_frame) child_process_logging::SetActiveURL(main_frame->url()); - // If this is developer tools renderer intercept tools messages first. - if (devtools_client_.get() && devtools_client_->OnMessageReceived(message)) - return true; - if (devtools_agent_.get() && devtools_agent_->OnMessageReceived(message)) - return true; - if (notification_provider_->OnMessageReceived(message)) - return true; - if (geolocation_dispatcher_.get() && - geolocation_dispatcher_->OnMessageReceived(message)) { - return true; - } - if (speech_input_dispatcher_.get() && - speech_input_dispatcher_->OnMessageReceived(message)) { - return true; - } - if (device_orientation_dispatcher_.get() && - device_orientation_dispatcher_->OnMessageReceived(message)) { - return true; - } + ObserverListBase<RenderViewObserver>::Iterator it(observers_); + RenderViewObserver* observer; + while ((observer = it.GetNext()) != NULL) + if (observer->OnMessageReceived(message)) + return true; bool handled = true; IPC_BEGIN_MESSAGE_MAP(RenderView, message) @@ -1019,7 +1022,6 @@ bool RenderView::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER(ViewMsg_CSSInsertRequest, OnCSSInsertRequest) IPC_MESSAGE_HANDLER(ViewMsg_AddMessageToConsole, OnAddMessageToConsole) IPC_MESSAGE_HANDLER(ViewMsg_ReservePageIDRange, OnReservePageIDRange) - IPC_MESSAGE_HANDLER(ViewMsg_FillPasswordForm, OnFillPasswordForm) IPC_MESSAGE_HANDLER(ViewMsg_DragTargetDragEnter, OnDragTargetDragEnter) IPC_MESSAGE_HANDLER(ViewMsg_DragTargetDragOver, OnDragTargetDragOver) IPC_MESSAGE_HANDLER(ViewMsg_DragTargetDragLeave, OnDragTargetDragLeave) @@ -1053,10 +1055,6 @@ bool RenderView::OnMessageReceived(const IPC::Message& message) { OnHandleMessageFromExternalHost) IPC_MESSAGE_HANDLER(ViewMsg_DisassociateFromPopupCount, OnDisassociateFromPopupCount) - IPC_MESSAGE_HANDLER(ViewMsg_AutoFillSuggestionsReturned, - OnAutoFillSuggestionsReturned) - IPC_MESSAGE_HANDLER(ViewMsg_AutoFillFormDataFilled, - OnAutoFillFormDataFilled) IPC_MESSAGE_HANDLER(ViewMsg_AllowScriptToClose, OnAllowScriptToClose) IPC_MESSAGE_HANDLER(ViewMsg_MoveOrResizeStarted, OnMoveOrResizeStarted) @@ -1378,12 +1376,6 @@ void RenderView::OnNavigate(const ViewMsg_Navigate_Params& params) { history_list_offset_ = params.current_history_list_offset; history_list_length_ = params.current_history_list_length; - if (devtools_agent_.get()) - devtools_agent_->OnNavigate(); - - if (notification_provider_.get()) - notification_provider_->OnNavigate(); - child_process_logging::SetActiveURL(params.url); AboutHandler::MaybeHandle(params.url); @@ -1504,8 +1496,8 @@ void RenderView::OnExecuteEditCommand(const std::string& name, } void RenderView::OnSetupDevToolsClient() { - DCHECK(!devtools_client_.get()); - devtools_client_.reset(new DevToolsClient(this)); + DCHECK(!devtools_client_); + devtools_client_ = new DevToolsClient(this); } void RenderView::OnUpdateTargetURLAck() { @@ -1982,21 +1974,6 @@ void RenderView::AddGURLSearchProvider( provider_type)); } -void RenderView::OnAutoFillSuggestionsReturned( - int query_id, - const std::vector<string16>& values, - const std::vector<string16>& labels, - const std::vector<string16>& icons, - const std::vector<int>& unique_ids) { - autofill_helper_->SuggestionsReceived( - query_id, values, labels, icons, unique_ids); -} - -void RenderView::OnAutoFillFormDataFilled(int query_id, - const webkit_glue::FormData& form) { - autofill_helper_->FormDataFilled(query_id, form); -} - void RenderView::OnAllowScriptToClose(bool script_can_close) { script_can_close_ = script_can_close; } @@ -2195,7 +2172,7 @@ void RenderView::printPage(WebFrame* frame) { } WebKit::WebNotificationPresenter* RenderView::notificationPresenter() { - return notification_provider_.get(); + return notification_provider_; } void RenderView::didStartLoading() { @@ -2300,29 +2277,6 @@ void RenderView::didExecuteCommand(const WebString& command_name) { UserMetricsRecordAction(name); } -void RenderView::textFieldDidEndEditing( - const WebKit::WebInputElement& element) { - password_autocomplete_manager_->TextFieldDidEndEditing(element); -} - -void RenderView::textFieldDidChange(const WebKit::WebInputElement& element) { - // We post a task for doing the AutoFill as the caret position is not set - // properly at this point (http://bugs.webkit.org/show_bug.cgi?id=16976) and - // it is needed to trigger autofill. - autofill_method_factory_.RevokeAll(); - MessageLoop::current()->PostTask( - FROM_HERE, - autofill_method_factory_.NewRunnableMethod( - &RenderView::TextFieldDidChangeImpl, element)); -} - -void RenderView::TextFieldDidChangeImpl( - const WebKit::WebInputElement& element) { - if (password_autocomplete_manager_->TextDidChangeInTextField(element)) - return; - autofill_helper_->TextDidChangeInTextField(element); -} - void RenderView::SendPendingAccessibilityNotifications() { if (!accessibility_.get()) return; @@ -2350,13 +2304,6 @@ void RenderView::SendPendingAccessibilityNotifications() { accessibility_ack_pending_ = true; } -void RenderView::textFieldDidReceiveKeyDown( - const WebKit::WebInputElement& element, - const WebKit::WebKeyboardEvent& event) { - password_autocomplete_manager_->TextFieldHandlingKeyDown(element, event); - autofill_helper_->KeyDownInTextField(element, event); -} - bool RenderView::handleCurrentKeyboardEvent() { if (edit_commands_.empty()) return false; @@ -2649,43 +2596,6 @@ void RenderView::didUpdateInspectorSetting(const WebString& key, value.utf8())); } -void RenderView::didAcceptAutoFillSuggestion(const WebKit::WebNode& node, - const WebKit::WebString& value, - const WebKit::WebString& label, - int unique_id, - unsigned index) { - autofill_helper_->DidAcceptAutoFillSuggestion(node, value, unique_id, index); -} - -void RenderView::didSelectAutoFillSuggestion(const WebKit::WebNode& node, - const WebKit::WebString& value, - const WebKit::WebString& label, - int unique_id) { - autofill_helper_->DidSelectAutoFillSuggestion(node, unique_id); -} - -void RenderView::didClearAutoFillSelection(const WebKit::WebNode& node) { - autofill_helper_->DidClearAutoFillSelection(node); -} - -void RenderView::didAcceptAutocompleteSuggestion( - const WebKit::WebInputElement& user_element) { - bool result = password_autocomplete_manager_->FillPassword(user_element); - // Since this user name was selected from a suggestion list, we should always - // have password for it. - DCHECK(result); -} - -void RenderView::removeAutocompleteSuggestion(const WebKit::WebString& name, - const WebKit::WebString& value) { - autofill_helper_->RemoveAutocompleteSuggestion(name, value); -} - -void RenderView::removeAutofillSuggestions(const WebString& name, - const WebString& value) { - removeAutocompleteSuggestion(name, value); -} - // WebKit::WebWidgetClient ---------------------------------------------------- void RenderView::didFocus() { @@ -2941,8 +2851,7 @@ WebCookieJar* RenderView::cookieJar(WebFrame* frame) { } void RenderView::frameDetached(WebFrame* frame) { - autofill_helper_->FrameDetached(frame); - page_click_tracker_->StopTrackingFrame(frame, true); + FOR_EACH_OBSERVER(RenderViewObserver, observers_, FrameDetached(frame)); } void RenderView::willClose(WebFrame* frame) { @@ -2952,11 +2861,7 @@ void RenderView::willClose(WebFrame* frame) { page_load_histograms_.Dump(frame); navigation_state->user_script_idle_scheduler()->Cancel(); - // TODO(jhawkins): Remove once frameDetached is called by WebKit. - // NOTE: taking this out results in lots of increased memory usage! This is - // because frameDetached is NOT like wilLClose. The latter happens between - // navigations, but the former only happens when the RenderView is going away. - autofill_helper_->FrameWillClose(frame); + FOR_EACH_OBSERVER(RenderViewObserver, observers_, FrameWillClose(frame)); } bool RenderView::allowImages(WebFrame* frame, bool enabled_per_settings) { @@ -3550,11 +3455,8 @@ void RenderView::didFinishDocumentLoad(WebFrame* frame) { Send(new ViewHostMsg_DocumentLoadedInFrame(routing_id_, frame->identifier())); - page_click_tracker_->StartTrackingFrame(frame); - // The document has now been fully loaded. Scan for forms to be sent up to - // the browser. - autofill_helper_->FrameContentsAvailable(frame); - password_autocomplete_manager_->SendPasswordForms(frame, false); + FOR_EACH_OBSERVER( + RenderViewObserver, observers_, DidFinishDocumentLoad(frame)); // Check whether we have new encoding name. UpdateEncoding(frame, frame->view()->pageEncoding().utf8()); @@ -3605,8 +3507,7 @@ void RenderView::didFinishLoad(WebFrame* frame) { navigation_state->set_finish_load_time(Time::Now()); navigation_state->user_script_idle_scheduler()->DidFinishLoad(); - // Let the password manager know which password forms are actually visible. - password_autocomplete_manager_->SendPasswordForms(frame, true); + FOR_EACH_OBSERVER(RenderViewObserver, observers_, DidFinishLoad(frame)); Send(new ViewHostMsg_DidFinishLoad(routing_id_, frame->identifier())); } @@ -4720,12 +4621,6 @@ void RenderView::OnDragSourceSystemDragEnded() { webview()->dragSourceSystemDragEnded(); } -void RenderView::OnFillPasswordForm( - const webkit_glue::PasswordFormFillData& form_data) { - password_autocomplete_manager_->ReceivedPasswordFormFillData(webview(), - form_data); -} - void RenderView::OnDragTargetDragEnter(const WebDropData& drop_data, const gfx::Point& client_point, const gfx::Point& screen_point, @@ -5502,7 +5397,7 @@ void RenderView::DidHandleKeyEvent() { } void RenderView::DidHandleMouseEvent(const WebKit::WebMouseEvent& event) { - page_click_tracker_->DidHandleMouseEvent(event); + FOR_EACH_OBSERVER(RenderViewObserver, observers_, DidHandleMouseEvent(event)); } #if defined(OS_MACOSX) @@ -5660,27 +5555,26 @@ void RenderView::OnPageTranslated() { if (!frame) return; - // The page is translated, so try to extract the form data again. - autofill_helper_->FrameContentsAvailable(frame); + FOR_EACH_OBSERVER(RenderViewObserver, observers_, FrameTranslated(frame)); } WebKit::WebGeolocationClient* RenderView::geolocationClient() { - if (!geolocation_dispatcher_.get()) - geolocation_dispatcher_.reset(new GeolocationDispatcher(this)); - return geolocation_dispatcher_.get(); + if (!geolocation_dispatcher_) + geolocation_dispatcher_ = new GeolocationDispatcher(this); + return geolocation_dispatcher_; } WebKit::WebSpeechInputController* RenderView::speechInputController( WebKit::WebSpeechInputListener* listener) { - if (!speech_input_dispatcher_.get()) - speech_input_dispatcher_.reset(new SpeechInputDispatcher(this, listener)); - return speech_input_dispatcher_.get(); + if (!speech_input_dispatcher_) + speech_input_dispatcher_ = new SpeechInputDispatcher(this, listener); + return speech_input_dispatcher_; } WebKit::WebDeviceOrientationClient* RenderView::deviceOrientationClient() { - if (!device_orientation_dispatcher_.get()) - device_orientation_dispatcher_.reset(new DeviceOrientationDispatcher(this)); - return device_orientation_dispatcher_.get(); + if (!device_orientation_dispatcher_) + device_orientation_dispatcher_ = new DeviceOrientationDispatcher(this); + return device_orientation_dispatcher_; } void RenderView::zoomLimitsChanged(double minimum_level, double maximum_level) { diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h index 414cff8..0d91208 100644 --- a/chrome/renderer/render_view.h +++ b/chrome/renderer/render_view.h @@ -17,6 +17,7 @@ #include "base/basictypes.h" #include "base/gtest_prod_util.h" #include "base/linked_ptr.h" +#include "base/observer_list.h" #include "base/timer.h" #include "base/weak_ptr.h" #include "build/build_config.h" @@ -35,7 +36,6 @@ #include "chrome/renderer/renderer_webcookiejar_impl.h" #include "chrome/renderer/searchbox.h" #include "chrome/renderer/translate_helper.h" -#include "third_party/WebKit/WebKit/chromium/public/WebAutoFillClient.h" #include "third_party/WebKit/WebKit/chromium/public/WebConsoleMessage.h" #include "third_party/WebKit/WebKit/chromium/public/WebFileSystem.h" #include "third_party/WebKit/WebKit/chromium/public/WebFrameClient.h" @@ -55,7 +55,6 @@ #endif class AudioMessageFilter; -class AutoFillHelper; class BlockedPlugin; class CustomMenuListener; class DictionaryValue; @@ -73,10 +72,9 @@ class ListValue; class LoadProgressTracker; class NavigationState; class NotificationProvider; -class PageClickTracker; -class PasswordAutocompleteManager; class PepperDeviceTest; class PrintWebViewHelper; +class RenderViewObserver; class RenderViewVisitor; class SkBitmap; class SpeechInputDispatcher; @@ -174,7 +172,6 @@ typedef base::RefCountedData<int> SharedRenderViewCounter; // communication interface with an embedding application process // class RenderView : public RenderWidget, - public WebKit::WebAutoFillClient, public WebKit::WebViewClient, public WebKit::WebFrameClient, public WebKit::WebPageSerializerClient, @@ -239,10 +236,6 @@ class RenderView : public RenderWidget, send_content_state_immediately_ = value; } - PageClickTracker* page_click_tracker() const { - return page_click_tracker_.get(); - } - // May be NULL if client-side phishing detection is disabled. safe_browsing::PhishingClassifierDelegate* phishing_classifier_delegate() const { @@ -261,6 +254,10 @@ class RenderView : public RenderWidget, return search_box_; } + // Functions to add and remove observers for this object. + void AddObserver(RenderViewObserver* observer); + void RemoveObserver(RenderViewObserver* observer); + // Called from JavaScript window.external.AddSearchProvider() to add a // keyword for a provider described in the given OpenSearch document. void AddSearchProvider(const std::string& url, @@ -397,30 +394,6 @@ class RenderView : public RenderWidget, virtual bool OnMessageReceived(const IPC::Message& msg); - // WebKit::WebAutoFillClient implementation ---------------------------------- - virtual void didAcceptAutoFillSuggestion(const WebKit::WebNode& node, - const WebKit::WebString& value, - const WebKit::WebString& label, - int unique_id, - unsigned index); - virtual void didSelectAutoFillSuggestion(const WebKit::WebNode& node, - const WebKit::WebString& value, - const WebKit::WebString& label, - int unique_id); - virtual void didClearAutoFillSelection(const WebKit::WebNode& node); - virtual void didAcceptAutocompleteSuggestion( - const WebKit::WebInputElement& element); - virtual void removeAutocompleteSuggestion(const WebKit::WebString& name, - const WebKit::WebString& value); - // TODO(jam): remove this function after WebKit roll - virtual void removeAutofillSuggestions(const WebKit::WebString& name, - const WebKit::WebString& value); - virtual void textFieldDidEndEditing(const WebKit::WebInputElement& element); - virtual void textFieldDidChange(const WebKit::WebInputElement& element); - virtual void textFieldDidReceiveKeyDown( - const WebKit::WebInputElement& element, - const WebKit::WebKeyboardEvent& event); - // WebKit::WebWidgetClient implementation ------------------------------------ // Most methods are handled by RenderWidget. @@ -760,22 +733,18 @@ class RenderView : public RenderWidget, }; RenderView(RenderThreadBase* render_thread, - const WebPreferences& webkit_preferences, - int64 session_storage_namespace_id); + gfx::NativeViewId parent_hwnd, + int32 opener_id, + const RendererPreferences& renderer_prefs, + const WebPreferences& webkit_prefs, + SharedRenderViewCounter* counter, + int32 routing_id, + int64 session_storage_namespace_id, + const string16& frame_name); // Do not delete directly. This class is reference counted. virtual ~RenderView(); - // Initializes this view with the given parent and ID. The |routing_id| can be - // set to 'MSG_ROUTING_NONE' if the true ID is not yet known. In this case, - // CompleteInit must be called later with the true ID. - void Init(gfx::NativeViewId parent, - int32 opener_id, - const RendererPreferences& renderer_prefs, - SharedRenderViewCounter* counter, - int32 routing_id, - const string16& frame_name); - void UpdateURL(WebKit::WebFrame* frame); void UpdateTitle(WebKit::WebFrame* frame, const string16& title); void UpdateSessionHistory(WebKit::WebFrame* frame); @@ -833,10 +802,6 @@ class RenderView : public RenderWidget, void AddGURLSearchProvider(const GURL& osd_url, const ViewHostMsg_PageHasOSDD_Type& provider_type); - // Called in a posted task by textFieldDidChange() to work-around a WebKit bug - // http://bugs.webkit.org/show_bug.cgi?id=16976 - void TextFieldDidChangeImpl(const WebKit::WebInputElement& element); - // Send queued accessibility notifications from the renderer to the browser. void SendPendingAccessibilityNotifications(); @@ -856,18 +821,6 @@ class RenderView : public RenderWidget, void OnAsyncFileOpened(base::PlatformFileError error_code, IPC::PlatformFileForTransit file_for_transit, int message_id); - void OnAutocompleteSuggestionsReturned( - int query_id, - const std::vector<string16>& suggestions, - int default_suggestions_index); - void OnAutoFillFormDataFilled(int query_id, - const webkit_glue::FormData& form); - void OnAutoFillSuggestionsReturned( - int query_id, - const std::vector<string16>& values, - const std::vector<string16>& labels, - const std::vector<string16>& icons, - const std::vector<int>& unique_ids); void OnCancelDownload(int32 download_id); void OnClearFocusedNode(); void OnClosePage(const ViewMsg_ClosePage_Params& params); @@ -949,8 +902,6 @@ class RenderView : public RenderWidget, void OnMoveOrResizeStarted(); void OnNavigate(const ViewMsg_Navigate_Params& params); void OnNotifyRendererViewType(ViewType::Type view_type); - void OnFillPasswordForm( - const webkit_glue::PasswordFormFillData& form_data); void OnPaste(); #if defined(OS_MACOSX) void OnPluginImeCompositionConfirmed(const string16& text, int plugin_id); @@ -1386,36 +1337,35 @@ class RenderView : public RenderWidget, // Helper objects ------------------------------------------------------------ ScopedRunnableMethodFactory<RenderView> page_info_method_factory_; - ScopedRunnableMethodFactory<RenderView> autofill_method_factory_; ScopedRunnableMethodFactory<RenderView> accessibility_method_factory_; // Responsible for translating the page contents to other languages. TranslateHelper translate_helper_; - // Responsible for automatically filling login and password textfields. - scoped_ptr<PasswordAutocompleteManager> password_autocomplete_manager_; - - // Responsible for filling forms (AutoFill) and single text entries - // (Autocomplete). - scoped_ptr<AutoFillHelper> autofill_helper_; - - // Tracks when text input controls get clicked. - // IMPORTANT: this should be declared after autofill_helper_ and - // password_autocomplete_manager_ so the tracker is deleted first (so we won't - // run the risk of notifying deleted objects). - scoped_ptr<PageClickTracker> page_click_tracker_; - RendererWebCookieJarImpl cookie_jar_; + // The next group of objects all implement RenderViewObserver, so are deleted + // along with the RenderView automatically. This is why we just store weak + // references. + // Provides access to this renderer from the remote Inspector UI. - scoped_ptr<DevToolsAgent> devtools_agent_; + DevToolsAgent* devtools_agent_; // DevToolsClient for renderer hosting developer tools UI. It's NULL for other // render views. - scoped_ptr<DevToolsClient> devtools_client_; + DevToolsClient* devtools_client_; // Holds a reference to the service which provides desktop notifications. - scoped_ptr<NotificationProvider> notification_provider_; + NotificationProvider* notification_provider_; + + // The geolocation dispatcher attached to this view, lazily initialized. + GeolocationDispatcher* geolocation_dispatcher_; + + // The speech dispatcher attached to this view, lazily initialized. + SpeechInputDispatcher* speech_input_dispatcher_; + + // Device orientation dispatcher attached to this view; lazily initialized. + DeviceOrientationDispatcher* device_orientation_dispatcher_; // PrintWebViewHelper handles printing. Note that this object is constructed // when printing for the first time but only destroyed with the RenderView. @@ -1423,9 +1373,6 @@ class RenderView : public RenderWidget, scoped_refptr<AudioMessageFilter> audio_message_filter_; - // The geolocation dispatcher attached to this view, lazily initialized. - scoped_ptr<GeolocationDispatcher> geolocation_dispatcher_; - // Handles accessibility requests into the renderer side, as well as // maintains the cache and other features of the accessibility tree. scoped_ptr<WebKit::WebAccessibilityCache> accessibility_; @@ -1438,12 +1385,6 @@ class RenderView : public RenderWidget, // Set if we are waiting for a accessibility notification ack. bool accessibility_ack_pending_; - // The speech dispatcher attached to this view, lazily initialized. - scoped_ptr<SpeechInputDispatcher> speech_input_dispatcher_; - - // Device orientation dispatcher attached to this view; lazily initialized. - scoped_ptr<DeviceOrientationDispatcher> device_orientation_dispatcher_; - // Responsible for sending page load related histograms. PageLoadHistograms page_load_histograms_; @@ -1529,11 +1470,17 @@ class RenderView : public RenderWidget, // Reports load progress to the browser. scoped_ptr<LoadProgressTracker> load_progress_tracker_; + // All the registered observers. We expect this list to be small, so vector + // is fine. + ObserverList<RenderViewObserver> observers_; + // --------------------------------------------------------------------------- // ADDING NEW DATA? Please see if it fits appropriately in one of the above // sections rather than throwing it randomly at the end. If you're adding a // bunch of stuff, you should probably create a helper class and put your - // data and methods on that to avoid bloating RenderView more. + // data and methods on that to avoid bloating RenderView more. You can use + // the Observer interface to filter IPC messages and receive frame change + // notifications. // --------------------------------------------------------------------------- DISALLOW_COPY_AND_ASSIGN(RenderView); diff --git a/chrome/renderer/render_view_browsertest.cc b/chrome/renderer/render_view_browsertest.cc index 379407d..01298b8 100644 --- a/chrome/renderer/render_view_browsertest.cc +++ b/chrome/renderer/render_view_browsertest.cc @@ -12,6 +12,7 @@ #include "chrome/common/native_web_keyboard_event.h" #include "chrome/common/render_messages.h" #include "chrome/common/render_messages_params.h" +#include "chrome/renderer/autofill_helper.h" #include "chrome/renderer/print_web_view_helper.h" #include "chrome/test/render_view_test.h" #include "gfx/codec/jpeg_codec.h" @@ -1025,7 +1026,7 @@ TEST_F(RenderViewTest, SendForms) { // Verify that "FormsSeen" sends the expected number of fields. ProcessPendingMessages(); - const IPC::Message* message = render_thread_.sink().GetUniqueMessageMatching( + const IPC::Message* message = render_thread_.sink().GetFirstMessageMatching( ViewHostMsg_FormsSeen::ID); ASSERT_NE(static_cast<IPC::Message*>(NULL), message); ViewHostMsg_FormsSeen::Param params; @@ -1065,11 +1066,12 @@ TEST_F(RenderViewTest, SendForms) { // Accept suggestion that contains a label. Labeled items indicate AutoFill // as opposed to Autocomplete. We're testing this distinction below with // the |ViewHostMsg_FillAutoFillFormData::ID| message. - view_->didAcceptAutoFillSuggestion(firstname, - WebKit::WebString::fromUTF8("Johnny"), - WebKit::WebString::fromUTF8("Home"), - 1, - -1); + autofill_helper_->didAcceptAutoFillSuggestion( + firstname, + WebKit::WebString::fromUTF8("Johnny"), + WebKit::WebString::fromUTF8("Home"), + 1, + -1); ProcessPendingMessages(); const IPC::Message* message2 = render_thread_.sink().GetUniqueMessageMatching( @@ -1115,7 +1117,7 @@ TEST_F(RenderViewTest, FillFormElement) { // Verify that "FormsSeen" sends the expected number of fields. ProcessPendingMessages(); - const IPC::Message* message = render_thread_.sink().GetUniqueMessageMatching( + const IPC::Message* message = render_thread_.sink().GetFirstMessageMatching( ViewHostMsg_FormsSeen::ID); ASSERT_NE(static_cast<IPC::Message*>(NULL), message); ViewHostMsg_FormsSeen::Param params; @@ -1150,11 +1152,12 @@ TEST_F(RenderViewTest, FillFormElement) { // Accept a suggestion in a form that has been auto-filled. This triggers // the direct filling of the firstname element with value parameter. - view_->didAcceptAutoFillSuggestion(firstname, - WebKit::WebString::fromUTF8("David"), - WebKit::WebString(), - 0, - 0); + autofill_helper_->didAcceptAutoFillSuggestion( + firstname, + WebKit::WebString::fromUTF8("David"), + WebKit::WebString(), + 0, + 0); ProcessPendingMessages(); const IPC::Message* message2 = render_thread_.sink().GetUniqueMessageMatching( diff --git a/chrome/renderer/render_view_observer.cc b/chrome/renderer/render_view_observer.cc new file mode 100644 index 0000000..7e771e3 --- /dev/null +++ b/chrome/renderer/render_view_observer.cc @@ -0,0 +1,33 @@ +// Copyright (c) 2011 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 "chrome/renderer/render_view_observer.h" + +#include "chrome/renderer/render_view.h" + +RenderViewObserver::RenderViewObserver(RenderView* render_view) + : render_view_(render_view), routing_id_(render_view->routing_id()) { + render_view_->AddObserver(this); +} + +RenderViewObserver::~RenderViewObserver() { + if (render_view_) + render_view_->RemoveObserver(this); +} + +void RenderViewObserver::OnDestruct() { + delete this; +} + +bool RenderViewObserver::OnMessageReceived(const IPC::Message& message) { + return false; +} + +bool RenderViewObserver::Send(IPC::Message* message) { + if (render_view_) + return render_view_->Send(message); + + delete message; + return false; +} diff --git a/chrome/renderer/render_view_observer.h b/chrome/renderer/render_view_observer.h new file mode 100644 index 0000000..be0d85f --- /dev/null +++ b/chrome/renderer/render_view_observer.h @@ -0,0 +1,63 @@ +// Copyright (c) 2011 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 CHROME_RENDERER_RENDER_VIEW_OBSERVER_H_ +#define CHROME_RENDERER_RENDER_VIEW_OBSERVER_H_ +#pragma once + +#include "base/basictypes.h" +#include "ipc/ipc_channel.h" + +class RenderView; + +namespace WebKit { +class WebFrame; +class WebMouseEvent; +} + +// Base class for objects that want to filter incoming IPCs, and also get +// notified of changes to the frame. +class RenderViewObserver : public IPC::Channel::Listener, + public IPC::Message::Sender { + public: + // By default, observers will be deleted when the RenderView goes away. If + // they want to outlive it, they can override this function. + virtual void OnDestruct(); + + // These match the WebKit API notifications. + virtual void DidFinishDocumentLoad(WebKit::WebFrame* frame) {} + virtual void DidFinishLoad(WebKit::WebFrame* frame) {} + virtual void FrameDetached(WebKit::WebFrame* frame) {} + virtual void FrameWillClose(WebKit::WebFrame* frame) {} + + // These match the RenderView methods below. + virtual void FrameTranslated(WebKit::WebFrame* frame) {} + virtual void DidHandleMouseEvent(const WebKit::WebMouseEvent& event) {} + + protected: + RenderViewObserver(RenderView* render_view); + virtual ~RenderViewObserver(); + + // IPC::Channel::Listener implementation. + virtual bool OnMessageReceived(const IPC::Message& message); + + // IPC::Message::Sender implementation. + virtual bool Send(IPC::Message* message); + + RenderView* render_view() { return render_view_; } + int routing_id() { return routing_id_; } + + private: + friend class RenderView; + + void set_render_view(RenderView* rv) { render_view_ = rv; } + + RenderView* render_view_; + // The routing ID of the associated RenderView. + int routing_id_; + + DISALLOW_COPY_AND_ASSIGN(RenderViewObserver); +}; + +#endif // CHROME_RENDERER_RENDER_VIEW_OBSERVER_H_ diff --git a/chrome/renderer/speech_input_dispatcher.cc b/chrome/renderer/speech_input_dispatcher.cc index d119621..6ce90b3 100644 --- a/chrome/renderer/speech_input_dispatcher.cc +++ b/chrome/renderer/speech_input_dispatcher.cc @@ -15,8 +15,9 @@ using WebKit::WebFrame; SpeechInputDispatcher::SpeechInputDispatcher( - RenderView* render_view, WebKit::WebSpeechInputListener* listener) - : render_view_(render_view), + RenderView* render_view, + WebKit::WebSpeechInputListener* listener) + : RenderViewObserver(render_view), listener_(listener) { } @@ -40,11 +41,11 @@ bool SpeechInputDispatcher::startRecognition( const WebKit::WebString& language, const WebKit::WebString& grammar) { VLOG(1) << "SpeechInputDispatcher::startRecognition enter"; - gfx::Size scroll = render_view_->webview()->mainFrame()->scrollOffset(); + gfx::Size scroll = render_view()->webview()->mainFrame()->scrollOffset(); gfx::Rect rect = element_rect; rect.Offset(-scroll.width(), -scroll.height()); - render_view_->Send(new ViewHostMsg_SpeechInput_StartRecognition( - render_view_->routing_id(), request_id, rect, + Send(new ViewHostMsg_SpeechInput_StartRecognition( + routing_id(), request_id, rect, UTF16ToUTF8(language), UTF16ToUTF8(grammar))); VLOG(1) << "SpeechInputDispatcher::startRecognition exit"; return true; @@ -52,15 +53,13 @@ bool SpeechInputDispatcher::startRecognition( void SpeechInputDispatcher::cancelRecognition(int request_id) { VLOG(1) << "SpeechInputDispatcher::cancelRecognition enter"; - render_view_->Send(new ViewHostMsg_SpeechInput_CancelRecognition( - render_view_->routing_id(), request_id)); + Send(new ViewHostMsg_SpeechInput_CancelRecognition(routing_id(), request_id)); VLOG(1) << "SpeechInputDispatcher::cancelRecognition exit"; } void SpeechInputDispatcher::stopRecording(int request_id) { VLOG(1) << "SpeechInputDispatcher::stopRecording enter"; - render_view_->Send(new ViewHostMsg_SpeechInput_StopRecording( - render_view_->routing_id(), request_id)); + Send(new ViewHostMsg_SpeechInput_StopRecording(routing_id(), request_id)); VLOG(1) << "SpeechInputDispatcher::stopRecording exit"; } diff --git a/chrome/renderer/speech_input_dispatcher.h b/chrome/renderer/speech_input_dispatcher.h index e993226..d5a3ce4 100644 --- a/chrome/renderer/speech_input_dispatcher.h +++ b/chrome/renderer/speech_input_dispatcher.h @@ -7,28 +7,26 @@ #include "base/basictypes.h" #include "chrome/common/speech_input_result.h" -#include "ipc/ipc_channel.h" +#include "chrome/renderer/render_view_observer.h" #include "third_party/WebKit/WebKit/chromium/public/WebSpeechInputController.h" class GURL; -class RenderView; namespace WebKit { class WebSpeechInputListener; -class WebString; -struct WebRect; } // SpeechInputDispatcher is a delegate for speech input messages used by WebKit. // It's the complement of SpeechInputDispatcherHost (owned by RenderViewHost). -class SpeechInputDispatcher : public WebKit::WebSpeechInputController, - public IPC::Channel::Listener { +class SpeechInputDispatcher : public RenderViewObserver, + public WebKit::WebSpeechInputController { public: SpeechInputDispatcher(RenderView* render_view, WebKit::WebSpeechInputListener* listener); - // IPC::Channel::Listener implementation. - bool OnMessageReceived(const IPC::Message& msg); + private: + // RenderView::Observer implementation. + bool OnMessageReceived(const IPC::Message& message); // WebKit::WebSpeechInputController. virtual bool startRecognition(int request_id, @@ -39,13 +37,11 @@ class SpeechInputDispatcher : public WebKit::WebSpeechInputController, virtual void cancelRecognition(int request_id); virtual void stopRecording(int request_id); - private: void OnSpeechRecognitionResult( int request_id, const speech_input::SpeechInputResultArray& result); void OnSpeechRecordingComplete(int request_id); void OnSpeechRecognitionComplete(int request_id); - RenderView* render_view_; WebKit::WebSpeechInputListener* listener_; DISALLOW_COPY_AND_ASSIGN(SpeechInputDispatcher); diff --git a/chrome/test/render_view_test.cc b/chrome/test/render_view_test.cc index 47a7c53..bfacc61 100644 --- a/chrome/test/render_view_test.cc +++ b/chrome/test/render_view_test.cc @@ -11,11 +11,13 @@ #include "chrome/common/render_messages.h" #include "chrome/common/render_messages_params.h" #include "chrome/common/renderer_preferences.h" +#include "chrome/renderer/autofill_helper.h" #include "chrome/renderer/extensions/event_bindings.h" #include "chrome/renderer/extensions/extension_process_bindings.h" #include "chrome/renderer/extensions/js_only_v8_extensions.h" #include "chrome/renderer/extensions/renderer_extension_bindings.h" #include "chrome/renderer/mock_render_process.h" +#include "chrome/renderer/password_autocomplete_manager.h" #include "chrome/renderer/renderer_main_platform_delegate.h" #include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" #include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h" @@ -135,6 +137,12 @@ void RenderViewTest::SetUp() { // Attach a pseudo keyboard device to this object. mock_keyboard_.reset(new MockKeyboard()); + + // RenderView doesn't expose it's PasswordAutocompleteManager or + // AutoFillHelper objects, because it has no need to store them directly + // (they're stored as RenderViewObserver*). So just create another set. + password_autocomplete_ = new PasswordAutocompleteManager(view_); + autofill_helper_ = new AutoFillHelper(view_, password_autocomplete_); } void RenderViewTest::TearDown() { @@ -245,7 +253,7 @@ void RenderViewTest::SendNativeKeyEvent( scoped_ptr<IPC::Message> input_message(new ViewMsg_HandleInputEvent(0)); input_message->WriteData(reinterpret_cast<const char*>(&key_event), sizeof(WebKit::WebKeyboardEvent)); - view_->OnHandleInputEvent(*input_message); + view_->OnMessageReceived(*input_message); } void RenderViewTest::VerifyPageCount(int count) { @@ -338,8 +346,9 @@ bool RenderViewTest::SimulateElementClick(const std::string& element_id) { mouse_event.y = bounds.CenterPoint().y(); mouse_event.clickCount = 1; ViewMsg_HandleInputEvent input_event(0); - input_event.WriteData(reinterpret_cast<const char*>(&mouse_event), - sizeof(WebMouseEvent)); - view_->OnHandleInputEvent(input_event); + scoped_ptr<IPC::Message> input_message(new ViewMsg_HandleInputEvent(0)); + input_message->WriteData(reinterpret_cast<const char*>(&mouse_event), + sizeof(WebMouseEvent)); + view_->OnMessageReceived(*input_message); return true; } diff --git a/chrome/test/render_view_test.h b/chrome/test/render_view_test.h index bb3e498..3528d40 100644 --- a/chrome/test/render_view_test.h +++ b/chrome/test/render_view_test.h @@ -21,7 +21,9 @@ #include "testing/gtest/include/gtest/gtest.h" #include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" +class AutoFillHelper; class MockRenderProcess; +class PasswordAutocompleteManager; class RenderViewTest : public testing::Test { public: @@ -99,6 +101,9 @@ class RenderViewTest : public testing::Test { scoped_ptr<MainFunctionParams> params_; scoped_ptr<CommandLine> command_line_; scoped_ptr<SandboxInitWrapper> sandbox_init_wrapper_; + + PasswordAutocompleteManager* password_autocomplete_; + AutoFillHelper* autofill_helper_; }; #endif // CHROME_TEST_RENDER_VIEW_TEST_H_ |