diff options
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_ |