summaryrefslogtreecommitdiffstats
path: root/chrome/browser/renderer_host
diff options
context:
space:
mode:
authorbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-01-22 17:48:25 +0000
committerbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-01-22 17:48:25 +0000
commit6524b5f9cb595b601fe95396439508efc7ecc8b3 (patch)
treed3b028ebba0b8a223ce0508131d8b69fe5f85354 /chrome/browser/renderer_host
parentc8159813d30739744a18e901f5ac27ac27424bb4 (diff)
downloadchromium_src-6524b5f9cb595b601fe95396439508efc7ecc8b3.zip
chromium_src-6524b5f9cb595b601fe95396439508efc7ecc8b3.tar.gz
chromium_src-6524b5f9cb595b601fe95396439508efc7ecc8b3.tar.bz2
Move files out of browser and into either renderer_host or tab_contents.
This also fixes a crash in the web contents unit test in a commented-out test and re-enable it. Review URL: http://codereview.chromium.org/18504 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@8470 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/renderer_host')
-rw-r--r--chrome/browser/renderer_host/browser_render_process_host.cc6
-rw-r--r--chrome/browser/renderer_host/cross_site_resource_handler.cc2
-rw-r--r--chrome/browser/renderer_host/render_view_host.cc1310
-rw-r--r--chrome/browser/renderer_host/render_view_host.h628
-rw-r--r--chrome/browser/renderer_host/render_view_host_delegate.h396
-rw-r--r--chrome/browser/renderer_host/render_widget_helper.cc235
-rw-r--r--chrome/browser/renderer_host/render_widget_helper.h159
-rw-r--r--chrome/browser/renderer_host/render_widget_host.cc849
-rw-r--r--chrome/browser/renderer_host/render_widget_host.h369
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view.h121
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_win.cc925
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_win.h283
-rw-r--r--chrome/browser/renderer_host/renderer_security_policy.cc285
-rw-r--r--chrome/browser/renderer_host/renderer_security_policy.h122
-rw-r--r--chrome/browser/renderer_host/renderer_security_policy_unittest.cc260
-rw-r--r--chrome/browser/renderer_host/resource_dispatcher_host.cc6
-rw-r--r--chrome/browser/renderer_host/test_render_view_host.cc6
-rw-r--r--chrome/browser/renderer_host/test_render_view_host.h10
18 files changed, 5961 insertions, 11 deletions
diff --git a/chrome/browser/renderer_host/browser_render_process_host.cc b/chrome/browser/renderer_host/browser_render_process_host.cc
index 7380510..a93cbbe 100644
--- a/chrome/browser/renderer_host/browser_render_process_host.cc
+++ b/chrome/browser/renderer_host/browser_render_process_host.cc
@@ -29,8 +29,8 @@
#include "chrome/browser/extensions/user_script_master.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/plugin_service.h"
-#include "chrome/browser/render_widget_helper.h"
-#include "chrome/browser/renderer_security_policy.h"
+#include "chrome/browser/renderer_host/render_widget_helper.h"
+#include "chrome/browser/renderer_host/renderer_security_policy.h"
#include "chrome/browser/resource_message_filter.h"
#include "chrome/browser/spellchecker.h"
#include "chrome/browser/visitedlink_master.h"
@@ -48,7 +48,7 @@
#if defined(OS_WIN)
// TODO(port): see comment by the only usage of RenderViewHost in this file.
-#include "chrome/browser/render_view_host.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
// Once the above TODO is finished, then this block is all Windows-specific
// files.
diff --git a/chrome/browser/renderer_host/cross_site_resource_handler.cc b/chrome/browser/renderer_host/cross_site_resource_handler.cc
index 91695df..a172352 100644
--- a/chrome/browser/renderer_host/cross_site_resource_handler.cc
+++ b/chrome/browser/renderer_host/cross_site_resource_handler.cc
@@ -4,7 +4,7 @@
#include "chrome/browser/renderer_host/cross_site_resource_handler.h"
-#include "chrome/browser/render_view_host.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_util.h"
#include "chrome/browser/tab_contents/web_contents.h"
diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc
new file mode 100644
index 0000000..dca1a1d
--- /dev/null
+++ b/chrome/browser/renderer_host/render_view_host.cc
@@ -0,0 +1,1310 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/renderer_host/render_view_host.h"
+
+#include <string>
+#include <vector>
+
+#include "base/string_util.h"
+#include "base/waitable_event.h"
+#include "chrome/app/result_codes.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/cross_site_request_manager.h"
+#include "chrome/browser/debugger/debugger_wrapper.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/renderer_host/render_process_host.h"
+#include "chrome/browser/renderer_host/render_view_host_delegate.h"
+#include "chrome/browser/renderer_host/render_widget_host.h"
+#include "chrome/browser/renderer_host/render_widget_host_view.h"
+#include "chrome/browser/renderer_host/renderer_security_policy.h"
+#include "chrome/browser/tab_contents/navigation_entry.h"
+#include "chrome/browser/tab_contents/site_instance.h"
+#include "chrome/browser/tab_contents/web_contents.h"
+#include "chrome/common/resource_bundle.h"
+#include "chrome/common/thumbnail_score.h"
+#include "net/base/net_util.h"
+#include "skia/include/SkBitmap.h"
+
+using base::TimeDelta;
+
+namespace {
+
+void FilterURL(RendererSecurityPolicy* policy, int renderer_id, GURL* url) {
+ if (!url->is_valid())
+ return; // We don't need to block invalid URLs.
+
+ if (url->SchemeIs("about")) {
+ // The renderer treats all URLs in the about: scheme as being about:blank.
+ // Canonicalize about: URLs to about:blank.
+ *url = GURL("about:blank");
+ }
+
+ if (!policy->CanRequestURL(renderer_id, *url)) {
+ // If this renderer is not permitted to request this URL, we invalidate the
+ // URL. This prevents us from storing the blocked URL and becoming confused
+ // later.
+ LOG(INFO) << "Blocked URL " << url->spec();
+ *url = GURL();
+ }
+}
+
+// Delay to wait on closing the tab for a beforeunload/unload handler to fire.
+const int kUnloadTimeoutMS = 1000;
+
+} // namespace
+
+///////////////////////////////////////////////////////////////////////////////
+// RenderViewHost, public:
+
+// static
+RenderViewHost* RenderViewHost::FromID(int render_process_id,
+ int render_view_id) {
+ RenderProcessHost* process = RenderProcessHost::FromID(render_process_id);
+ if (!process)
+ return NULL;
+ RenderWidgetHost* widget = static_cast<RenderWidgetHost*>(
+ process->GetListenerByID(render_view_id));
+ if (!widget || !widget->IsRenderView())
+ return NULL;
+ return static_cast<RenderViewHost*>(widget);
+}
+
+RenderViewHost::RenderViewHost(SiteInstance* instance,
+ RenderViewHostDelegate* delegate,
+ int routing_id,
+ base::WaitableEvent* modal_dialog_event)
+ : RenderWidgetHost(instance->GetProcess(), routing_id),
+ instance_(instance),
+ enable_dom_ui_bindings_(false),
+ enable_external_host_bindings_(false),
+ delegate_(delegate),
+ renderer_initialized_(false),
+ waiting_for_drag_context_response_(false),
+ debugger_attached_(false),
+ modal_dialog_count_(0),
+ navigations_suspended_(false),
+ suspended_nav_message_(NULL),
+ run_modal_reply_msg_(NULL),
+ has_unload_listener_(false),
+ is_waiting_for_unload_ack_(false),
+ are_javascript_messages_suppressed_(false) {
+ DCHECK(instance_);
+ DCHECK(delegate_);
+ if (modal_dialog_event == NULL)
+ modal_dialog_event = new base::WaitableEvent(true, false);
+
+ modal_dialog_event_.reset(modal_dialog_event);
+#ifdef CHROME_PERSONALIZATION
+ personalization_ = Personalization::CreateHostPersonalization(this);
+#endif
+}
+
+RenderViewHost::~RenderViewHost() {
+ OnDebugDisconnect();
+
+#ifdef CHROME_PERSONALIZATION
+ Personalization::CleanupHostPersonalization(personalization_);
+ personalization_ = NULL;
+#endif
+
+ // Be sure to clean up any leftover state from cross-site requests.
+ Singleton<CrossSiteRequestManager>()->SetHasPendingCrossSiteRequest(
+ process()->host_id(), routing_id_, false);
+}
+
+bool RenderViewHost::CreateRenderView() {
+ DCHECK(!IsRenderViewLive()) << "Creating view twice";
+
+ // The process may (if we're sharing a process with another host that already
+ // initialized it) or may not (we have our own process or the old process
+ // crashed) have been initialized. Calling Init multiple times will be
+ // ignored, so this is safe.
+ if (!process_->Init())
+ return false;
+ DCHECK(process_->channel());
+ DCHECK(process_->profile());
+
+ renderer_initialized_ = true;
+
+ HANDLE modal_dialog_event;
+ HANDLE renderer_process_handle = process()->process().handle();
+ if (renderer_process_handle == NULL)
+ renderer_process_handle = GetCurrentProcess();
+
+ BOOL result = DuplicateHandle(GetCurrentProcess(),
+ modal_dialog_event_->handle(),
+ renderer_process_handle,
+ &modal_dialog_event,
+ SYNCHRONIZE,
+ FALSE,
+ 0);
+ DCHECK(result) << "Couldn't duplicate the modal dialog handle for the renderer.";
+
+ DCHECK(view_);
+ Send(new ViewMsg_New(view_->GetPluginHWND(),
+ modal_dialog_event,
+ delegate_->GetWebkitPrefs(),
+ routing_id_));
+
+ // Set the alternate error page, which is profile specific, in the renderer.
+ GURL url = delegate_->GetAlternateErrorPageURL();
+ SetAlternateErrorPageURL(url);
+
+ // If it's enabled, tell the renderer to set up the Javascript bindings for
+ // sending messages back to the browser.
+ Send(new ViewMsg_AllowBindings(
+ routing_id_, enable_dom_ui_bindings_, enable_external_host_bindings_));
+
+ // Let our delegate know that we created a RenderView.
+ delegate_->RendererCreated(this);
+
+ return true;
+}
+
+bool RenderViewHost::IsRenderViewLive() const {
+ return process_->channel() && renderer_initialized_;
+}
+
+void RenderViewHost::Init() {
+ RenderWidgetHost::Init();
+ renderer_initialized_ = true;
+}
+
+void RenderViewHost::NavigateToEntry(const NavigationEntry& entry,
+ bool is_reload) {
+ ViewMsg_Navigate_Params params;
+ MakeNavigateParams(entry, is_reload, &params);
+
+ RendererSecurityPolicy::GetInstance()->GrantRequestURL(
+ process()->host_id(), params.url);
+
+ DoNavigate(new ViewMsg_Navigate(routing_id_, params));
+}
+
+void RenderViewHost::NavigateToURL(const GURL& url) {
+ ViewMsg_Navigate_Params params;
+ params.page_id = -1;
+ params.url = url;
+ params.transition = PageTransition::LINK;
+ params.reload = false;
+
+ RendererSecurityPolicy::GetInstance()->GrantRequestURL(
+ process()->host_id(), params.url);
+
+ DoNavigate(new ViewMsg_Navigate(routing_id_, params));
+}
+
+void RenderViewHost::DoNavigate(ViewMsg_Navigate* nav_message) {
+ // Only send the message if we aren't suspended at the start of a cross-site
+ // request.
+ if (navigations_suspended_) {
+ // Shouldn't be possible to have a second navigation while suspended, since
+ // navigations will only be suspended during a cross-site request. If a
+ // second navigation occurs, WebContents will cancel this pending RVH
+ // create a new pending RVH.
+ DCHECK(!suspended_nav_message_.get());
+ suspended_nav_message_.reset(nav_message);
+ } else {
+ Send(nav_message);
+ }
+}
+
+void RenderViewHost::LoadAlternateHTMLString(const std::string& html_text,
+ bool new_navigation,
+ const GURL& display_url,
+ const std::string& security_info) {
+ Send(new ViewMsg_LoadAlternateHTMLText(routing_id_, html_text,
+ new_navigation, display_url,
+ security_info));
+}
+
+void RenderViewHost::SetNavigationsSuspended(bool suspend) {
+ DCHECK(navigations_suspended_ != suspend);
+ navigations_suspended_ = suspend;
+ if (!suspend && suspended_nav_message_.get()) {
+ // Resume navigation
+ Send(suspended_nav_message_.release());
+ }
+}
+
+void RenderViewHost::FirePageBeforeUnload() {
+ if (!IsRenderViewLive()) {
+ // This RenderViewHost doesn't have a live renderer, so just skip running
+ // the onbeforeunload handler.
+ OnMsgShouldCloseACK(true);
+ return;
+ }
+
+ // This may be called more than once (if the user clicks the tab close button
+ // several times, or if she clicks the tab close button than the browser close
+ // button), so this test makes sure we only send the message once.
+ if (!is_waiting_for_unload_ack_) {
+ // Start the hang monitor in case the renderer hangs in the beforeunload
+ // handler.
+ is_waiting_for_unload_ack_ = true;
+ StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS));
+ Send(new ViewMsg_ShouldClose(routing_id_));
+ }
+}
+
+void RenderViewHost::FirePageUnload() {
+ ClosePage(site_instance()->process_host_id(),
+ routing_id());
+}
+
+// static
+void RenderViewHost::ClosePageIgnoringUnloadEvents(int render_process_host_id,
+ int request_id) {
+ RenderViewHost* rvh = RenderViewHost::FromID(render_process_host_id,
+ request_id);
+ if (!rvh)
+ return;
+
+ rvh->StopHangMonitorTimeout();
+ rvh->is_waiting_for_unload_ack_ = false;
+
+ rvh->UnloadListenerHasFired();
+ rvh->delegate()->Close(rvh);
+}
+
+void RenderViewHost::ClosePage(int new_render_process_host_id,
+ int new_request_id) {
+ // Start the hang monitor in case the renderer hangs in the unload handler.
+ is_waiting_for_unload_ack_ = true;
+ StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS));
+
+ if (IsRenderViewLive()) {
+ Send(new ViewMsg_ClosePage(routing_id_,
+ new_render_process_host_id,
+ new_request_id));
+ } else {
+ // This RenderViewHost doesn't have a live renderer, so just skip closing
+ // the page. We must notify the ResourceDispatcherHost on the IO thread,
+ // which we will do through the RenderProcessHost's widget helper.
+ process()->CrossSiteClosePageACK(new_render_process_host_id,
+ new_request_id);
+ }
+}
+
+void RenderViewHost::SetHasPendingCrossSiteRequest(bool has_pending_request,
+ int request_id) {
+ Singleton<CrossSiteRequestManager>()->SetHasPendingCrossSiteRequest(
+ process()->host_id(), routing_id_, has_pending_request);
+ pending_request_id_ = request_id;
+}
+
+int RenderViewHost::GetPendingRequestId() {
+ return pending_request_id_;
+}
+
+void RenderViewHost::OnCrossSiteResponse(int new_render_process_host_id,
+ int new_request_id) {
+ delegate_->OnCrossSiteResponse(new_render_process_host_id, new_request_id);
+}
+
+void RenderViewHost::Stop() {
+ Send(new ViewMsg_Stop(routing_id_));
+}
+
+bool RenderViewHost::GetPrintedPagesCount(const ViewMsg_Print_Params& params) {
+ return Send(new ViewMsg_GetPrintedPagesCount(routing_id_, params));
+}
+
+bool RenderViewHost::PrintPages(const ViewMsg_PrintPages_Params& params) {
+ return Send(new ViewMsg_PrintPages(routing_id_, params));
+}
+
+void RenderViewHost::StartFinding(int request_id,
+ const std::wstring& search_string,
+ bool forward,
+ bool match_case,
+ bool find_next) {
+ if (search_string.empty())
+ return;
+
+ FindInPageRequest request;
+ request.request_id = request_id;
+ request.search_string = search_string;
+ request.forward = forward;
+ request.match_case = match_case;
+ request.find_next = find_next;
+ Send(new ViewMsg_Find(routing_id_, request));
+
+ // This call is asynchronous and returns immediately.
+ // The result of the search is sent as a notification message by the renderer.
+}
+
+void RenderViewHost::StopFinding(bool clear_selection) {
+ Send(new ViewMsg_StopFinding(routing_id_, clear_selection));
+}
+
+void RenderViewHost::Zoom(PageZoom::Function function) {
+ Send(new ViewMsg_Zoom(routing_id_, function));
+}
+
+void RenderViewHost::SetPageEncoding(const std::wstring& encoding_name) {
+ Send(new ViewMsg_SetPageEncoding(routing_id_, encoding_name));
+}
+
+void RenderViewHost::SetAlternateErrorPageURL(const GURL& url) {
+ Send(new ViewMsg_SetAltErrorPageURL(routing_id_, url));
+}
+
+void RenderViewHost::FillForm(const FormData& form_data) {
+ Send(new ViewMsg_FormFill(routing_id_, form_data));
+}
+
+void RenderViewHost::FillPasswordForm(
+ const PasswordFormDomManager::FillData& form_data) {
+ Send(new ViewMsg_FillPasswordForm(routing_id_, form_data));
+}
+
+void RenderViewHost::DragTargetDragEnter(const WebDropData& drop_data,
+ const gfx::Point& client_pt, const gfx::Point& screen_pt) {
+ // Grant the renderer the ability to load the drop_data.
+ RendererSecurityPolicy* policy = RendererSecurityPolicy::GetInstance();
+ policy->GrantRequestURL(process()->host_id(), drop_data.url);
+ for (std::vector<std::wstring>::const_iterator iter(drop_data.filenames.begin());
+ iter != drop_data.filenames.end(); ++iter) {
+ policy->GrantRequestURL(process()->host_id(),
+ net::FilePathToFileURL(*iter));
+ policy->GrantUploadFile(process()->host_id(), *iter);
+ }
+ Send(new ViewMsg_DragTargetDragEnter(routing_id_, drop_data, client_pt,
+ screen_pt));
+}
+
+void RenderViewHost::DragTargetDragOver(
+ const gfx::Point& client_pt, const gfx::Point& screen_pt) {
+ Send(new ViewMsg_DragTargetDragOver(routing_id_, client_pt, screen_pt));
+}
+
+void RenderViewHost::DragTargetDragLeave() {
+ Send(new ViewMsg_DragTargetDragLeave(routing_id_));
+}
+
+void RenderViewHost::DragTargetDrop(
+ const gfx::Point& client_pt, const gfx::Point& screen_pt) {
+ Send(new ViewMsg_DragTargetDrop(routing_id_, client_pt, screen_pt));
+}
+
+void RenderViewHost::ReservePageIDRange(int size) {
+ Send(new ViewMsg_ReservePageIDRange(routing_id_, size));
+}
+
+void RenderViewHost::ExecuteJavascriptInWebFrame(
+ const std::wstring& frame_xpath, const std::wstring& jscript) {
+ Send(new ViewMsg_ScriptEvalRequest(routing_id_, frame_xpath, jscript));
+}
+
+void RenderViewHost::AddMessageToConsole(
+ const std::wstring& frame_xpath, const std::wstring& msg,
+ ConsoleMessageLevel level) {
+ Send(new ViewMsg_AddMessageToConsole(routing_id_, frame_xpath, msg, level));
+}
+
+void RenderViewHost::DebugCommand(const std::wstring& cmd) {
+ Send(new ViewMsg_DebugCommand(routing_id_, cmd));
+}
+
+void RenderViewHost::DebugAttach() {
+ if (!debugger_attached_)
+ Send(new ViewMsg_DebugAttach(routing_id_));
+}
+
+void RenderViewHost::DebugDetach() {
+ if (debugger_attached_) {
+ Send(new ViewMsg_DebugDetach(routing_id_));
+ debugger_attached_ = false;
+ }
+}
+
+void RenderViewHost::DebugBreak(bool force) {
+ if (debugger_attached_)
+ Send(new ViewMsg_DebugBreak(routing_id_, force));
+}
+
+void RenderViewHost::Undo() {
+ Send(new ViewMsg_Undo(routing_id_));
+}
+
+void RenderViewHost::Redo() {
+ Send(new ViewMsg_Redo(routing_id_));
+}
+
+void RenderViewHost::Cut() {
+ Send(new ViewMsg_Cut(routing_id_));
+}
+
+void RenderViewHost::Copy() {
+ Send(new ViewMsg_Copy(routing_id_));
+}
+
+void RenderViewHost::Paste() {
+ Send(new ViewMsg_Paste(routing_id_));
+}
+
+void RenderViewHost::Replace(const std::wstring& text_to_replace) {
+ Send(new ViewMsg_Replace(routing_id_, text_to_replace));
+}
+
+void RenderViewHost::ToggleSpellCheck() {
+ Send(new ViewMsg_ToggleSpellCheck(routing_id_));
+}
+
+void RenderViewHost::AddToDictionary(const std::wstring& word) {
+ process_->AddWord(word);
+}
+
+void RenderViewHost::Delete() {
+ Send(new ViewMsg_Delete(routing_id_));
+}
+
+void RenderViewHost::SelectAll() {
+ Send(new ViewMsg_SelectAll(routing_id_));
+}
+
+int RenderViewHost::DownloadImage(const GURL& url, int image_size) {
+ if (!url.is_valid()) {
+ NOTREACHED();
+ return 0;
+ }
+ static int next_id = 1;
+ int id = next_id++;
+ Send(new ViewMsg_DownloadImage(routing_id_, id, url, image_size));
+ return id;
+}
+
+void RenderViewHost::GetApplicationInfo(int32 page_id) {
+ Send(new ViewMsg_GetApplicationInfo(routing_id_, page_id));
+}
+
+void RenderViewHost::CaptureThumbnail() {
+ Send(new ViewMsg_CaptureThumbnail(routing_id_));
+}
+
+void RenderViewHost::JavaScriptMessageBoxClosed(IPC::Message* reply_msg,
+ bool success,
+ const std::wstring& prompt) {
+ if (is_waiting_for_unload_ack_) {
+ if (are_javascript_messages_suppressed_) {
+ delegate_->RendererUnresponsive(this, is_waiting_for_unload_ack_);
+ return;
+ }
+
+ StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS));
+ }
+
+ if (--modal_dialog_count_ == 0)
+ modal_dialog_event_->Reset();
+ ViewHostMsg_RunJavaScriptMessage::WriteReplyParams(reply_msg, success, prompt);
+ Send(reply_msg);
+}
+
+void RenderViewHost::ModalHTMLDialogClosed(IPC::Message* reply_msg,
+ const std::string& json_retval) {
+ if (is_waiting_for_unload_ack_)
+ StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kUnloadTimeoutMS));
+
+ if (--modal_dialog_count_ == 0)
+ modal_dialog_event_->Reset();
+
+ ViewHostMsg_ShowModalHTMLDialog::WriteReplyParams(reply_msg, json_retval);
+ Send(reply_msg);
+}
+
+void RenderViewHost::CopyImageAt(int x, int y) {
+ Send(new ViewMsg_CopyImageAt(routing_id_, x, y));
+}
+
+void RenderViewHost::InspectElementAt(int x, int y) {
+ RendererSecurityPolicy::GetInstance()->GrantInspectElement(
+ process()->host_id());
+ Send(new ViewMsg_InspectElement(routing_id_, x, y));
+}
+
+void RenderViewHost::ShowJavaScriptConsole() {
+ RendererSecurityPolicy::GetInstance()->GrantInspectElement(
+ process()->host_id());
+
+ Send(new ViewMsg_ShowJavaScriptConsole(routing_id_));
+}
+
+void RenderViewHost::DragSourceEndedAt(
+ int client_x, int client_y, int screen_x, int screen_y) {
+ Send(new ViewMsg_DragSourceEndedOrMoved(
+ routing_id_, client_x, client_y, screen_x, screen_y, true));
+}
+
+void RenderViewHost::DragSourceMovedTo(
+ int client_x, int client_y, int screen_x, int screen_y) {
+ Send(new ViewMsg_DragSourceEndedOrMoved(
+ routing_id_, client_x, client_y, screen_x, screen_y, false));
+}
+
+void RenderViewHost::DragSourceSystemDragEnded() {
+ Send(new ViewMsg_DragSourceSystemDragEnded(routing_id_));
+}
+
+void RenderViewHost::AllowDomAutomationBindings() {
+ // Expose the binding that allows the DOM to send messages here.
+ Send(new ViewMsg_AllowDomAutomationBindings(routing_id_, true));
+}
+
+void RenderViewHost::AllowDOMUIBindings() {
+ DCHECK(!renderer_initialized_);
+ enable_dom_ui_bindings_ = true;
+ RendererSecurityPolicy::GetInstance()->GrantDOMUIBindings(process()->host_id());
+}
+
+void RenderViewHost::AllowExternalHostBindings() {
+ enable_external_host_bindings_ = true;
+}
+
+void RenderViewHost::SetDOMUIProperty(const std::string& name,
+ const std::string& value) {
+ DCHECK(enable_dom_ui_bindings_);
+ Send(new ViewMsg_SetDOMUIProperty(routing_id_, name, value));
+}
+
+// static
+void RenderViewHost::MakeNavigateParams(const NavigationEntry& entry,
+ bool reload,
+ ViewMsg_Navigate_Params* params) {
+ params->page_id = entry.page_id();
+ params->url = entry.url();
+ params->referrer = entry.referrer();
+ params->transition = entry.transition_type();
+ params->state = entry.content_state();
+ params->reload = reload;
+}
+
+bool RenderViewHost::CanBlur() const {
+ return delegate_->CanBlur();
+}
+
+void RenderViewHost::SetInitialFocus(bool reverse) {
+ Send(new ViewMsg_SetInitialFocus(routing_id_, reverse));
+}
+
+void RenderViewHost::UpdateWebPreferences(const WebPreferences& prefs) {
+ Send(new ViewMsg_UpdateWebPreferences(routing_id_, prefs));
+}
+
+void RenderViewHost::InstallMissingPlugin() {
+ Send(new ViewMsg_InstallMissingPlugin(routing_id_));
+}
+
+void RenderViewHost::FileSelected(const std::wstring& path) {
+ RendererSecurityPolicy::GetInstance()->GrantUploadFile(process()->host_id(),
+ path);
+ std::vector<std::wstring> files;
+ files.push_back(path);
+ Send(new ViewMsg_RunFileChooserResponse(routing_id_, files));
+}
+
+void RenderViewHost::MultiFilesSelected(
+ const std::vector<std::wstring>& files) {
+ for (std::vector<std::wstring>::const_iterator file = files.begin();
+ file != files.end(); ++file) {
+ RendererSecurityPolicy::GetInstance()->GrantUploadFile(
+ process()->host_id(), *file);
+ }
+ Send(new ViewMsg_RunFileChooserResponse(routing_id_, files));
+}
+
+void RenderViewHost::LoadStateChanged(const GURL& url,
+ net::LoadState load_state) {
+ delegate_->LoadStateChanged(url, load_state);
+}
+
+bool RenderViewHost::CanTerminate() const {
+ if (!delegate_->CanTerminate())
+ return false;
+
+ return has_unload_listener_;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// RenderViewHost, IPC message handlers:
+
+void RenderViewHost::OnMessageReceived(const IPC::Message& msg) {
+ if (msg.is_sync() && !msg.is_caller_pumping_messages()) {
+ NOTREACHED() << "Can't send sync messages to UI thread without pumping " \
+ "messages in the renderer or else deadlocks can occur if the page" \
+ "has windowed plugins!";
+ IPC::Message* reply = IPC::SyncMessage::GenerateReply(&msg);
+ reply->set_reply_error();
+ Send(reply);
+ return;
+ }
+
+ bool msg_is_ok = true;
+ IPC_BEGIN_MESSAGE_MAP_EX(RenderViewHost, msg, msg_is_ok)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_CreateWindowWithRoute, OnMsgCreateWindow)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_CreateWidgetWithRoute, OnMsgCreateWidget)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_ShowView, OnMsgShowView)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_ShowWidget, OnMsgShowWidget)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_RunModal, OnMsgRunModal)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_RendererReady, OnMsgRendererReady)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_RendererGone, OnMsgRendererGone)
+ IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_FrameNavigate, OnMsgNavigate(msg))
+ IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateState, OnMsgUpdateState)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateTitle, OnMsgUpdateTitle)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateEncoding, OnMsgUpdateEncoding)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateTargetURL, OnMsgUpdateTargetURL)
+ IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_Thumbnail, OnMsgThumbnail(msg))
+ IPC_MESSAGE_HANDLER(ViewHostMsg_Close, OnMsgClose)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_RequestMove, OnMsgRequestMove)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DidStartLoading, OnMsgDidStartLoading)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DidStopLoading, OnMsgDidStopLoading)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DidLoadResourceFromMemoryCache,
+ OnMsgDidLoadResourceFromMemoryCache)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DidRedirectProvisionalLoad,
+ OnMsgDidRedirectProvisionalLoad)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DidStartProvisionalLoadForFrame,
+ OnMsgDidStartProvisionalLoadForFrame)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DidFailProvisionalLoadWithError,
+ OnMsgDidFailProvisionalLoadWithError)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_Find_Reply, OnMsgFindReply)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateFavIconURL, OnMsgUpdateFavIconURL)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DidDownloadImage, OnMsgDidDownloadImage)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_ContextMenu, OnMsgContextMenu)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_OpenURL, OnMsgOpenURL)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DomOperationResponse,
+ OnMsgDomOperationResponse)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DOMUISend,
+ OnMsgDOMUISend)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_ForwardMessageToExternalHost,
+ OnMsgForwardMessageToExternalHost)
+#ifdef CHROME_PERSONALIZATION
+ IPC_MESSAGE_HANDLER(ViewHostMsg_PersonalizationEvent,
+ OnPersonalizationEvent)
+#endif
+ IPC_MESSAGE_HANDLER(ViewHostMsg_GoToEntryAtOffset,
+ OnMsgGoToEntryAtOffset)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_SetTooltipText, OnMsgSetTooltipText)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_RunFileChooser, OnMsgRunFileChooser)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_RunJavaScriptMessage,
+ OnMsgRunJavaScriptMessage)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_RunBeforeUnloadConfirm,
+ OnMsgRunBeforeUnloadConfirm)
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_ShowModalHTMLDialog,
+ OnMsgShowModalHTMLDialog)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_PasswordFormsSeen, OnMsgPasswordFormsSeen)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_AutofillFormSubmitted,
+ OnMsgAutofillFormSubmitted)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_StartDragging, OnMsgStartDragging)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateDragCursor, OnUpdateDragCursor)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_TakeFocus, OnTakeFocus)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_PageHasOSDD, OnMsgPageHasOSDD)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_InspectElement_Reply,
+ OnMsgInspectElementReply)
+ IPC_MESSAGE_FORWARD(ViewHostMsg_DidGetPrintedPagesCount,
+ delegate_,
+ RenderViewHostDelegate::DidGetPrintedPagesCount)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DidPrintPage, DidPrintPage)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_AddMessageToConsole, OnAddMessageToConsole)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DebuggerOutput, OnDebuggerOutput);
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DidDebugAttach, DidDebugAttach);
+ IPC_MESSAGE_HANDLER(ViewHostMsg_UserMetricsRecordAction,
+ OnUserMetricsRecordAction)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_MissingPluginStatus, OnMissingPluginStatus);
+ IPC_MESSAGE_FORWARD(ViewHostMsg_CrashedPlugin, delegate_,
+ RenderViewHostDelegate::OnCrashedPlugin);
+ IPC_MESSAGE_HANDLER(ViewHostMsg_SendCurrentPageAllSavableResourceLinks,
+ OnReceivedSavableResourceLinksForCurrentPage);
+ IPC_MESSAGE_HANDLER(ViewHostMsg_SendSerializedHtmlData,
+ OnReceivedSerializedHtmlData);
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DidGetApplicationInfo,
+ OnDidGetApplicationInfo);
+ IPC_MESSAGE_FORWARD(ViewHostMsg_JSOutOfMemory, delegate_,
+ RenderViewHostDelegate::OnJSOutOfMemory);
+ IPC_MESSAGE_HANDLER(ViewHostMsg_ShouldClose_ACK, OnMsgShouldCloseACK);
+ IPC_MESSAGE_HANDLER(ViewHostMsg_UnloadListenerChanged,
+ OnUnloadListenerChanged);
+ IPC_MESSAGE_HANDLER(ViewHostMsg_QueryFormFieldAutofill,
+ OnQueryFormFieldAutofill)
+ // Have the super handle all other messages.
+ IPC_MESSAGE_UNHANDLED(RenderWidgetHost::OnMessageReceived(msg))
+ IPC_END_MESSAGE_MAP_EX()
+
+ if (!msg_is_ok) {
+ // The message had a handler, but its de-serialization failed.
+ // Kill the renderer.
+ process()->ReceivedBadMessage(msg.type());
+ }
+}
+
+void RenderViewHost::Shutdown() {
+ // If we are being run modally (see RunModal), then we need to cleanup.
+ if (run_modal_reply_msg_) {
+ if (--modal_dialog_count_ == 0)
+ modal_dialog_event_->Reset();
+ Send(run_modal_reply_msg_);
+ run_modal_reply_msg_ = NULL;
+ }
+ RenderWidgetHost::Shutdown();
+}
+
+void RenderViewHost::OnMsgCreateWindow(int route_id,
+ HANDLE modal_dialog_event) {
+ RenderViewHostDelegate::View* view = delegate_->GetViewDelegate();
+ if (view)
+ view->CreateNewWindow(route_id,
+ new base::WaitableEvent(modal_dialog_event));
+}
+
+void RenderViewHost::OnMsgCreateWidget(int route_id, bool activatable) {
+ RenderViewHostDelegate::View* view = delegate_->GetViewDelegate();
+ if (view)
+ view->CreateNewWidget(route_id, activatable);
+}
+
+void RenderViewHost::OnMsgShowView(int route_id,
+ WindowOpenDisposition disposition,
+ const gfx::Rect& initial_pos,
+ bool user_gesture) {
+ RenderViewHostDelegate::View* view = delegate_->GetViewDelegate();
+ if (view)
+ view->ShowCreatedWindow(route_id, disposition, initial_pos, user_gesture);
+}
+
+void RenderViewHost::OnMsgShowWidget(int route_id,
+ const gfx::Rect& initial_pos) {
+ RenderViewHostDelegate::View* view = delegate_->GetViewDelegate();
+ if (view)
+ view->ShowCreatedWidget(route_id, initial_pos);
+}
+
+void RenderViewHost::OnMsgRunModal(IPC::Message* reply_msg) {
+ DCHECK(!run_modal_reply_msg_);
+ if (modal_dialog_count_++ == 0)
+ modal_dialog_event_->Reset();
+ run_modal_reply_msg_ = reply_msg;
+
+ // TODO(darin): Bug 1107929: Need to inform our delegate to show this view in
+ // an app-modal fashion.
+}
+
+void RenderViewHost::OnMsgRendererReady() {
+ WasResized();
+ delegate_->RendererReady(this);
+}
+
+void RenderViewHost::OnMsgRendererGone() {
+ // Must reset these to ensure that mouse move events work with a new renderer.
+ mouse_move_pending_ = false;
+ next_mouse_move_.reset();
+
+ // Clearing this flag causes us to re-create the renderer when recovering
+ // from a crashed renderer.
+ renderer_initialized_ = false;
+
+ // Reset some fields in preparation for recovering from a crash.
+ resize_ack_pending_ = false;
+ current_size_ = gfx::Size();
+ is_hidden_ = false;
+
+ RendererExited();
+
+ if (view_) {
+ view_->RendererGone();
+ view_ = NULL; // The View should be deleted by RendererGone.
+ }
+ delegate_->RendererGone(this);
+ OnDebugDisconnect();
+}
+
+// Called when the renderer navigates. For every frame loaded, we'll get this
+// notification containing parameters identifying the navigation.
+//
+// Subframes are identified by the page transition type. For subframes loaded
+// as part of a wider page load, the page_id will be the same as for the top
+// level frame. If the user explicitly requests a subframe navigation, we will
+// get a new page_id because we need to create a new navigation entry for that
+// action.
+void RenderViewHost::OnMsgNavigate(const IPC::Message& msg) {
+ // Read the parameters out of the IPC message directly to avoid making another
+ // copy when we filter the URLs.
+ void* iter = NULL;
+ ViewHostMsg_FrameNavigate_Params validated_params;
+ if (!IPC::ParamTraits<ViewHostMsg_FrameNavigate_Params>::
+ Read(&msg, &iter, &validated_params))
+ return;
+
+ const int renderer_id = process()->host_id();
+ RendererSecurityPolicy* policy = RendererSecurityPolicy::GetInstance();
+ // Without this check, an evil renderer can trick the browser into creating
+ // a navigation entry for a banned URL. If the user clicks the back button
+ // followed by the forward button (or clicks reload, or round-trips through
+ // session restore, etc), we'll think that the browser commanded the
+ // renderer to load the URL and grant the renderer the privileges to request
+ // the URL. To prevent this attack, we block the renderer from inserting
+ // banned URLs into the navigation controller in the first place.
+ FilterURL(policy, renderer_id, &validated_params.url);
+ FilterURL(policy, renderer_id, &validated_params.referrer);
+ for (std::vector<GURL>::iterator it(validated_params.redirects.begin());
+ it != validated_params.redirects.end(); ++it) {
+ FilterURL(policy, renderer_id, &(*it));
+ }
+ FilterURL(policy, renderer_id, &validated_params.searchable_form_url);
+ FilterURL(policy, renderer_id, &validated_params.password_form.origin);
+ FilterURL(policy, renderer_id, &validated_params.password_form.action);
+
+ delegate_->DidNavigate(this, validated_params);
+
+ UpdateBackForwardListCount();
+}
+
+void RenderViewHost::OnMsgUpdateState(int32 page_id,
+ const std::string& state) {
+ delegate_->UpdateState(this, page_id, state);
+}
+
+void RenderViewHost::OnMsgUpdateTitle(int32 page_id,
+ const std::wstring& title) {
+ delegate_->UpdateTitle(this, page_id, title);
+}
+
+void RenderViewHost::OnMsgUpdateEncoding(const std::wstring& encoding_name) {
+ delegate_->UpdateEncoding(this, encoding_name);
+}
+
+void RenderViewHost::OnMsgUpdateTargetURL(int32 page_id,
+ const GURL& url) {
+ delegate_->UpdateTargetURL(page_id, url);
+
+ // Send a notification back to the renderer that we are ready to
+ // receive more target urls.
+ Send(new ViewMsg_UpdateTargetURL_ACK(routing_id_));
+}
+
+void RenderViewHost::OnMsgThumbnail(const IPC::Message& msg) {
+ // crack the message
+ void* iter = NULL;
+ GURL url;
+ if (!IPC::ParamTraits<GURL>::Read(&msg, &iter, &url))
+ return;
+
+ ThumbnailScore score;
+ if (!IPC::ParamTraits<ThumbnailScore>::Read(&msg, &iter, &score))
+ return;
+
+ // thumbnail data
+ SkBitmap bitmap;
+ if (!IPC::ParamTraits<SkBitmap>::Read(&msg, &iter, &bitmap))
+ return;
+
+ delegate_->UpdateThumbnail(url, bitmap, score);
+}
+
+void RenderViewHost::OnMsgClose() {
+ delegate_->Close(this);
+}
+
+void RenderViewHost::OnMsgRequestMove(const gfx::Rect& pos) {
+ delegate_->RequestMove(pos);
+}
+
+void RenderViewHost::OnMsgDidRedirectProvisionalLoad(int32 page_id,
+ const GURL& source_url,
+ const GURL& target_url) {
+ delegate_->DidRedirectProvisionalLoad(page_id, source_url, target_url);
+}
+
+void RenderViewHost::OnMsgDidStartLoading(int32 page_id) {
+ delegate_->DidStartLoading(this, page_id);
+
+ if (view_) {
+ view_->UpdateCursorIfOverSelf();
+ }
+}
+
+void RenderViewHost::OnMsgDidStopLoading(int32 page_id) {
+ delegate_->DidStopLoading(this, page_id);
+
+ if (view_) {
+ view_->UpdateCursorIfOverSelf();
+ }
+}
+
+void RenderViewHost::OnMsgDidLoadResourceFromMemoryCache(
+ const GURL& url,
+ const std::string& security_info) {
+ delegate_->DidLoadResourceFromMemoryCache(url, security_info);
+}
+
+void RenderViewHost::OnMsgDidStartProvisionalLoadForFrame(bool is_main_frame,
+ const GURL& url) {
+ GURL validated_url(url);
+ FilterURL(RendererSecurityPolicy::GetInstance(),
+ process()->host_id(), &validated_url);
+
+ delegate_->DidStartProvisionalLoadForFrame(this, is_main_frame, validated_url);
+}
+
+void RenderViewHost::OnMsgDidFailProvisionalLoadWithError(
+ bool is_main_frame,
+ int error_code,
+ const GURL& url,
+ bool showing_repost_interstitial) {
+ GURL validated_url(url);
+ FilterURL(RendererSecurityPolicy::GetInstance(),
+ process()->host_id(), &validated_url);
+
+ delegate_->DidFailProvisionalLoadWithError(this, is_main_frame,
+ error_code, validated_url,
+ showing_repost_interstitial);
+}
+
+void RenderViewHost::OnMsgFindReply(int request_id,
+ int number_of_matches,
+ const gfx::Rect& selection_rect,
+ int active_match_ordinal,
+ bool final_update) {
+ RenderViewHostDelegate::View* view = delegate_->GetViewDelegate();
+ if (!view)
+ return;
+ view->OnFindReply(request_id, number_of_matches, selection_rect,
+ active_match_ordinal, final_update);
+
+ // Send a notification to the renderer that we are ready to receive more
+ // results from the scoping effort of the Find operation. The FindInPage
+ // scoping is asynchronous and periodically sends results back up to the
+ // browser using IPC. In an effort to not spam the browser we have the
+ // browser send an ACK for each FindReply message and have the renderer
+ // queue up the latest status message while waiting for this ACK.
+ Send(new ViewMsg_FindReplyACK(routing_id_));
+}
+
+void RenderViewHost::OnMsgUpdateFavIconURL(int32 page_id,
+ const GURL& icon_url) {
+ delegate_->UpdateFavIconURL(this, page_id, icon_url);
+}
+
+void RenderViewHost::OnMsgDidDownloadImage(
+ int id,
+ const GURL& image_url,
+ bool errored,
+ const SkBitmap& image) {
+ delegate_->DidDownloadImage(this, id, image_url, errored, image);
+}
+
+void RenderViewHost::OnMsgContextMenu(
+ const ViewHostMsg_ContextMenu_Params& params) {
+ RenderViewHostDelegate::View* view = delegate_->GetViewDelegate();
+ if (!view)
+ return;
+
+ // Validate the URLs in |params|. If the renderer can't request the URLs
+ // directly, don't show them in the context menu.
+ ViewHostMsg_ContextMenu_Params validated_params(params);
+ const int renderer_id = process()->host_id();
+ RendererSecurityPolicy* policy = RendererSecurityPolicy::GetInstance();
+
+ FilterURL(policy, renderer_id, &validated_params.link_url);
+ FilterURL(policy, renderer_id, &validated_params.image_url);
+ FilterURL(policy, renderer_id, &validated_params.page_url);
+ FilterURL(policy, renderer_id, &validated_params.frame_url);
+
+ view->ShowContextMenu(validated_params);
+}
+
+void RenderViewHost::OnMsgOpenURL(const GURL& url,
+ const GURL& referrer,
+ WindowOpenDisposition disposition) {
+ GURL validated_url(url);
+ FilterURL(RendererSecurityPolicy::GetInstance(),
+ process()->host_id(), &validated_url);
+
+ delegate_->RequestOpenURL(validated_url, referrer, disposition);
+}
+
+void RenderViewHost::OnMsgDomOperationResponse(
+ const std::string& json_string, int automation_id) {
+ delegate_->DomOperationResponse(json_string, automation_id);
+}
+
+void RenderViewHost::OnMsgDOMUISend(
+ const std::string& message, const std::string& content) {
+ if (!RendererSecurityPolicy::GetInstance()->
+ HasDOMUIBindings(process()->host_id())) {
+ NOTREACHED() << "Blocked unauthorized use of DOMUIBindings.";
+ return;
+ }
+ delegate_->ProcessDOMUIMessage(message, content);
+}
+
+void RenderViewHost::OnMsgForwardMessageToExternalHost(
+ const std::string& receiver,
+ const std::string& message) {
+ delegate_->ProcessExternalHostMessage(receiver, message);
+}
+
+#ifdef CHROME_PERSONALIZATION
+void RenderViewHost::OnPersonalizationEvent(const std::string& message,
+ const std::string& content) {
+ Personalization::HandlePersonalizationEvent(this, message, content);
+}
+#endif
+
+void RenderViewHost::DisassociateFromPopupCount() {
+ Send(new ViewMsg_DisassociateFromPopupCount(routing_id_));
+}
+
+void RenderViewHost::PopupNotificationVisibilityChanged(bool visible) {
+ Send(new ViewMsg_PopupNotificationVisiblityChanged(routing_id_, visible));
+}
+
+void RenderViewHost::OnMsgGoToEntryAtOffset(int offset) {
+ delegate_->GoToEntryAtOffset(offset);
+}
+
+void RenderViewHost::OnMsgSetTooltipText(const std::wstring& tooltip_text) {
+ if (view_) {
+ view_->SetTooltipText(tooltip_text);
+ }
+}
+
+void RenderViewHost::OnMsgRunFileChooser(bool multiple_files,
+ const std::wstring& title,
+ const std::wstring& default_file,
+ const std::wstring& filter) {
+ std::wstring real_filter = filter;
+ std::replace(real_filter.begin(), real_filter.end(), '|', '\0');
+ delegate_->RunFileChooser(multiple_files, title, default_file, real_filter);
+}
+
+void RenderViewHost::OnMsgRunJavaScriptMessage(
+ const std::wstring& message,
+ const std::wstring& default_prompt,
+ const int flags,
+ IPC::Message* reply_msg) {
+ StopHangMonitorTimeout();
+ if (modal_dialog_count_++ == 0)
+ modal_dialog_event_->Signal();
+ bool did_suppress_message = false;
+ delegate_->RunJavaScriptMessage(message, default_prompt, flags, reply_msg,
+ &are_javascript_messages_suppressed_);
+}
+
+void RenderViewHost::OnMsgRunBeforeUnloadConfirm(const std::wstring& message,
+ IPC::Message* reply_msg) {
+ StopHangMonitorTimeout();
+ if (modal_dialog_count_++ == 0)
+ modal_dialog_event_->Signal();
+ delegate_->RunBeforeUnloadConfirm(message, reply_msg);
+}
+
+void RenderViewHost::OnMsgShowModalHTMLDialog(
+ const GURL& url, int width, int height, const std::string& json_arguments,
+ IPC::Message* reply_msg) {
+ StopHangMonitorTimeout();
+ if (modal_dialog_count_++ == 0)
+ modal_dialog_event_->Signal();
+ delegate_->ShowModalHTMLDialog(url, width, height, json_arguments, reply_msg);
+}
+
+void RenderViewHost::OnMsgPasswordFormsSeen(
+ const std::vector<PasswordForm>& forms) {
+ delegate_->PasswordFormsSeen(forms);
+}
+
+void RenderViewHost::OnMsgAutofillFormSubmitted(
+ const AutofillForm& form) {
+ delegate_->AutofillFormSubmitted(form);
+}
+
+void RenderViewHost::OnMsgStartDragging(
+ const WebDropData& drop_data) {
+ RenderViewHostDelegate::View* view = delegate_->GetViewDelegate();
+ if (view)
+ view->StartDragging(drop_data);
+}
+
+void RenderViewHost::OnUpdateDragCursor(bool is_drop_target) {
+ RenderViewHostDelegate::View* view = delegate_->GetViewDelegate();
+ if (view)
+ view->UpdateDragCursor(is_drop_target);
+}
+
+void RenderViewHost::OnTakeFocus(bool reverse) {
+ RenderViewHostDelegate::View* view = delegate_->GetViewDelegate();
+ if (view)
+ view->TakeFocus(reverse);
+}
+
+void RenderViewHost::OnMsgPageHasOSDD(int32 page_id, const GURL& doc_url,
+ bool autodetected) {
+ delegate_->PageHasOSDD(this, page_id, doc_url, autodetected);
+}
+
+void RenderViewHost::OnMsgInspectElementReply(int num_resources) {
+ delegate_->InspectElementReply(num_resources);
+}
+
+void RenderViewHost::DidPrintPage(
+ const ViewHostMsg_DidPrintPage_Params& params) {
+ delegate_->DidPrintPage(params);
+}
+
+void RenderViewHost::OnAddMessageToConsole(const std::wstring& message,
+ int32 line_no,
+ const std::wstring& source_id) {
+ std::wstring msg = StringPrintf(L"\"%ls,\" source: %ls (%d)", message.c_str(),
+ source_id.c_str(), line_no);
+ logging::LogMessage("CONSOLE", 0).stream() << msg;
+ if (debugger_attached_)
+ g_browser_process->debugger_wrapper()->DebugMessage(msg);
+}
+
+void RenderViewHost::OnDebuggerOutput(const std::wstring& output) {
+ if (debugger_attached_)
+ g_browser_process->debugger_wrapper()->DebugMessage(output);
+}
+
+void RenderViewHost::DidDebugAttach() {
+ if (!debugger_attached_) {
+ debugger_attached_ = true;
+ g_browser_process->debugger_wrapper()->OnDebugAttach();
+ }
+}
+
+void RenderViewHost::OnUserMetricsRecordAction(const std::wstring& action) {
+ UserMetrics::RecordComputedAction(action.c_str(), process_->profile());
+}
+
+void RenderViewHost::UnhandledInputEvent(const WebInputEvent& event) {
+ RenderViewHostDelegate::View* view = delegate_->GetViewDelegate();
+ if (view) {
+ // TODO(brettw) why do we have to filter these types of events here. Can't
+ // the renderer just send us the ones we care abount, or maybe the view
+ // should be able to decide which ones it wants or not?
+ if ((event.type == WebInputEvent::KEY_DOWN) ||
+ (event.type == WebInputEvent::CHAR)) {
+ view->HandleKeyboardEvent(
+ static_cast<const WebKeyboardEvent&>(event));
+ }
+ }
+}
+
+void RenderViewHost::ForwardKeyboardEvent(const WebKeyboardEvent& key_event) {
+ if (key_event.type == WebKeyboardEvent::CHAR &&
+ (key_event.key_code == VK_RETURN || key_event.key_code == VK_SPACE)) {
+ delegate_->OnEnterOrSpace();
+ }
+ RenderWidgetHost::ForwardKeyboardEvent(key_event);
+}
+
+void RenderViewHost::OnMissingPluginStatus(int status) {
+ delegate_->OnMissingPluginStatus(status);
+}
+
+void RenderViewHost::UpdateBackForwardListCount() {
+ int back_list_count, forward_list_count;
+ delegate_->GetHistoryListCount(&back_list_count, &forward_list_count);
+ Send(new ViewMsg_UpdateBackForwardListCount(
+ routing_id_, back_list_count, forward_list_count));
+}
+
+void RenderViewHost::GetAllSavableResourceLinksForCurrentPage(
+ const GURL& page_url) {
+ Send(new ViewMsg_GetAllSavableResourceLinksForCurrentPage(routing_id_,
+ page_url));
+}
+
+void RenderViewHost::OnReceivedSavableResourceLinksForCurrentPage(
+ const std::vector<GURL>& resources_list,
+ const std::vector<GURL>& referrers_list,
+ const std::vector<GURL>& frames_list) {
+ RenderViewHostDelegate::Save* save_delegate = delegate_->GetSaveDelegate();
+ if (save_delegate) {
+ save_delegate->OnReceivedSavableResourceLinksForCurrentPage(
+ resources_list, referrers_list, frames_list);
+ }
+}
+
+void RenderViewHost::OnDidGetApplicationInfo(
+ int32 page_id,
+ const webkit_glue::WebApplicationInfo& info) {
+ delegate_->OnDidGetApplicationInfo(page_id, info);
+}
+
+void RenderViewHost::GetSerializedHtmlDataForCurrentPageWithLocalLinks(
+ const std::vector<std::wstring>& links,
+ const std::vector<std::wstring>& local_paths,
+ const std::wstring& local_directory_name) {
+ Send(new ViewMsg_GetSerializedHtmlDataForCurrentPageWithLocalLinks(
+ routing_id_, links, local_paths, local_directory_name));
+}
+
+void RenderViewHost::OnReceivedSerializedHtmlData(const GURL& frame_url,
+ const std::string& data,
+ int32 status) {
+ RenderViewHostDelegate::Save* save_delegate = delegate_->GetSaveDelegate();
+ if (save_delegate)
+ save_delegate->OnReceivedSerializedHtmlData(frame_url, data, status);
+}
+
+void RenderViewHost::OnMsgShouldCloseACK(bool proceed) {
+ StopHangMonitorTimeout();
+ DCHECK(is_waiting_for_unload_ack_);
+ is_waiting_for_unload_ack_ = false;
+ delegate_->ShouldClosePage(proceed);
+}
+
+void RenderViewHost::OnUnloadListenerChanged(bool has_listener) {
+ has_unload_listener_ = has_listener;
+}
+
+void RenderViewHost::OnQueryFormFieldAutofill(const std::wstring& field_name,
+ const std::wstring& user_text,
+ int64 node_id,
+ int request_id) {
+ delegate_->GetAutofillSuggestions(field_name, user_text, node_id, request_id);
+}
+
+void RenderViewHost::AutofillSuggestionsReturned(
+ const std::vector<std::wstring>& suggestions,
+ int64 node_id, int request_id, int default_suggestion_index) {
+ Send(new ViewMsg_AutofillSuggestions(routing_id_, node_id,
+ request_id, suggestions, -1));
+ // Default index -1 means no default suggestion.
+}
+
+void RenderViewHost::NotifyRendererUnresponsive() {
+ // If the debugger is attached, we're going to be unresponsive anytime it's
+ // stopped at a breakpoint.
+ if (!debugger_attached_) {
+ delegate_->RendererUnresponsive(this, is_waiting_for_unload_ack_);
+ }
+}
+
+void RenderViewHost::NotifyRendererResponsive() {
+ delegate_->RendererResponsive(this);
+}
+
+void RenderViewHost::OnDebugDisconnect() {
+ if (debugger_attached_) {
+ debugger_attached_ = false;
+ g_browser_process->debugger_wrapper()->OnDebugDisconnect();
+ }
+}
+
+#ifdef CHROME_PERSONALIZATION
+void RenderViewHost::RaisePersonalizationEvent(std::string event_name,
+ std::string event_arg) {
+ Send(new ViewMsg_PersonalizationEvent(routing_id_,
+ event_name,
+ event_arg));
+}
+#endif
+
+void RenderViewHost::ForwardMessageFromExternalHost(
+ const std::string& target, const std::string& message) {
+ Send(new ViewMsg_HandleMessageFromExternalHost(routing_id_, target, message));
+}
diff --git a/chrome/browser/renderer_host/render_view_host.h b/chrome/browser/renderer_host/render_view_host.h
new file mode 100644
index 0000000..4ae497f
--- /dev/null
+++ b/chrome/browser/renderer_host/render_view_host.h
@@ -0,0 +1,628 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_RENDER_VIEW_HOST_H__
+#define CHROME_BROWSER_RENDER_VIEW_HOST_H__
+
+#include <string>
+#include <vector>
+
+#include "base/scoped_ptr.h"
+#include "chrome/browser/renderer_host/render_view_host_delegate.h"
+#include "chrome/browser/renderer_host/render_widget_host.h"
+#include "chrome/common/page_zoom.h"
+#ifdef CHROME_PERSONALIZATION
+#include "chrome/personalization/personalization.h"
+#endif
+#include "webkit/glue/password_form_dom_manager.h"
+#include "webkit/glue/autofill_form.h"
+
+enum ConsoleMessageLevel;
+class NavigationEntry;
+class RenderViewHostDelegate;
+class SiteInstance;
+class SkBitmap;
+struct ViewHostMsg_ContextMenu_Params;
+struct ViewHostMsg_DidPrintPage_Params;
+class ViewMsg_Navigate;
+struct ViewMsg_Navigate_Params;
+struct ViewMsg_Print_Params;
+struct ViewMsg_PrintPages_Params;
+struct WebDropData;
+struct WebPreferences;
+enum WindowOpenDisposition;
+
+namespace base {
+class WaitableEvent;
+}
+
+namespace gfx {
+class Point;
+}
+
+namespace net {
+enum LoadState;
+}
+
+namespace webkit_glue {
+struct WebApplicationInfo;
+}
+
+//
+// RenderViewHost
+//
+// A RenderViewHost is responsible for creating and talking to a RenderView
+// object in a child process. It exposes a high level API to users, for things
+// like loading pages, adjusting the display and other browser functionality,
+// which it translates into IPC messages sent over the IPC channel with the
+// RenderView. It responds to all IPC messages sent by that RenderView and
+// cracks them, calling a delegate object back with higher level types where
+// possible.
+//
+// The intent of this class is to provide a view-agnostic communication
+// conduit with a renderer. This is so we can build HTML views not only as
+// TabContents (see WebContents for an example) but also as views, etc.
+//
+// The exact API of this object needs to be more thoroughly designed. Right
+// now it mimics what WebContents exposed, which is a fairly large API and may
+// contain things that are not relevant to a common subset of views. See also
+// the comment in render_view_host_delegate.h about the size and scope of the
+// delegate API.
+//
+// Right now, the concept of page navigation (both top level and frame) exists
+// in the WebContents still, so if you instantiate one of these elsewhere, you
+// will not be able to traverse pages back and forward. We need to determine
+// if we want to bring that and other functionality down into this object so
+// it can be shared by others.
+//
+class RenderViewHost : public RenderWidgetHost {
+ public:
+ // Returns the RenderViewHost given its ID and the ID of its render process.
+ // Returns NULL if the IDs do not correspond to a live RenderViewHost.
+ static RenderViewHost* FromID(int render_process_id, int render_view_id);
+
+ // routing_id could be a valid route id, or it could be MSG_ROUTING_NONE, in
+ // which case RenderWidgetHost will create a new one. modal_dialog_event is
+ // the event that's set when showing a modal dialog so that the renderer and
+ // plugin processes know to pump messages. An existing event can be passed
+ // in, otherwise if it's NULL a new event will be created.
+ explicit RenderViewHost(SiteInstance* instance,
+ RenderViewHostDelegate* delegate,
+ int routing_id,
+ base::WaitableEvent* modal_dialog_event);
+ virtual ~RenderViewHost();
+
+ SiteInstance* site_instance() const { return instance_; }
+ RenderViewHostDelegate* delegate() const { return delegate_; }
+
+ // Set up the RenderView child process.
+ virtual bool CreateRenderView();
+ // Returns true if the RenderView is active and has not crashed.
+ virtual bool IsRenderViewLive() const;
+ // Create a new RenderViewHost but recycle an existing RenderView child
+ // process.
+ virtual void Init();
+
+ // Load the specified entry, optionally reloading.
+ virtual void NavigateToEntry(const NavigationEntry& entry, bool is_reload);
+
+ // Load the specified URL.
+ void NavigateToURL(const GURL& url);
+
+ // Loads the specified html (must be UTF8) in the main frame. If
+ // |new_navigation| is true, it simulates a navigation to |display_url|.
+ // |security_info| is the security state that will be reported when the page
+ // load commits. It is useful for mocking SSL errors. Provide an empty
+ // string if no secure connection state should be simulated.
+ // Note that if |new_navigation| is false, |display_url| and |security_info|
+ // are not used.
+ virtual void LoadAlternateHTMLString(const std::string& html_text,
+ bool new_navigation,
+ const GURL& display_url,
+ const std::string& security_info);
+
+ // Suspends (or unsuspends) any navigation messages from being sent from this
+ // RenderViewHost. This is called when a pending RenderViewHost is created
+ // for a cross-site navigation, because we must suspend any navigations until
+ // we hear back from the old renderer's onbeforeunload handler. Note that it
+ // is important that only one navigation event happen after calling this
+ // method with |suspend| equal to true. If |suspend| is false and there is
+ // a suspended_nav_message_, this will send the message.
+ void SetNavigationsSuspended(bool suspend);
+
+ // Causes the renderer to invoke the onbeforeunload event handler. The
+ // result will be returned via ViewMsg_ShouldClose.
+ virtual void FirePageBeforeUnload();
+
+ // Close the page after the page has responded that it can be closed via
+ // ViewMsg_ShouldClose. This is where the page itself is closed. The
+ // unload handler is triggered here, which can block with a dialog, but cannot
+ // cancel the close of the page.
+ void FirePageUnload();
+
+ // Close the page ignoring whether it has unload events registers.
+ // This is called after the beforeunload and unload events have fired
+ // and the user has agreed to continue with closing the page.
+ static void ClosePageIgnoringUnloadEvents(int render_process_host_id,
+ int request_id);
+
+ // Causes the renderer to close the current page, including running its
+ // onunload event handler. A ClosePage_ACK message will be sent to the
+ // ResourceDispatcherHost when it is finished. |new_render_process_host_id|
+ // and |new_request_id| will help the ResourceDispatcherHost identify which
+ // response is associated with this event.
+ virtual void ClosePage(int new_render_process_host_id,
+ int new_request_id);
+
+ // Sets whether this RenderViewHost has an outstanding cross-site request,
+ // for which another renderer will need to run an onunload event handler.
+ // This is called before the first navigation event for this RenderViewHost,
+ // and again after the corresponding OnCrossSiteResponse.
+ void SetHasPendingCrossSiteRequest(bool has_pending_request, int request_id);
+
+ // Returns the request_id for the pending cross-site request.
+ // This is just needed in case the unload of the current page
+ // hangs, in which case we need to swap to the pending RenderViewHost.
+ int GetPendingRequestId();
+
+ // Called by ResourceDispatcherHost when a response for a pending cross-site
+ // request is received. The ResourceDispatcherHost will pause the response
+ // until the onunload handler of the previous renderer is run.
+ void OnCrossSiteResponse(int new_render_process_host_id, int new_request_id);
+
+ // Stops the current load.
+ void Stop();
+
+
+ // Retrieves the number of printed pages that would result for the current web
+ // page and the specified settings. The response is a
+ // ViewHostMsg_DidGetPrintedPagesCount.
+ bool GetPrintedPagesCount(const ViewMsg_Print_Params& params);
+
+ // Asks the renderer to "render" printed pages.
+ bool PrintPages(const ViewMsg_PrintPages_Params& params);
+
+ // Start looking for a string within the content of the page, with the
+ // specified options.
+ void StartFinding(int request_id,
+ const std::wstring& search_string,
+ bool forward,
+ bool match_case,
+ bool find_next);
+
+ // Cancel a pending find operation. If |clear_selection| is true, it will also
+ // clear the selection on the focused frame.
+ void StopFinding(bool clear_selection);
+
+ // Change the zoom level of a page.
+ void Zoom(PageZoom::Function function);
+
+ // Change the encoding of the page.
+ void SetPageEncoding(const std::wstring& encoding);
+
+ // Change the alternate error page URL. An empty GURL disables the use of
+ // alternate error pages.
+ void SetAlternateErrorPageURL(const GURL& url);
+
+ // Fill out a form within the page with the specified data.
+ void FillForm(const FormData& form_data);
+
+ // Fill out a password form and trigger DOM autocomplete in the case
+ // of multiple matching logins.
+ void FillPasswordForm(const PasswordFormDomManager::FillData& form_data);
+
+ // D&d drop target messages that get sent to WebKit.
+ void DragTargetDragEnter(const WebDropData& drop_data,
+ const gfx::Point& client_pt,
+ const gfx::Point& screen_pt);
+ void DragTargetDragOver(const gfx::Point& client_pt,
+ const gfx::Point& screen_pt);
+ void DragTargetDragLeave();
+ void DragTargetDrop(const gfx::Point& client_pt,
+ const gfx::Point& screen_pt);
+
+ // Tell the RenderView to reserve a range of page ids of the given size.
+ void ReservePageIDRange(int size);
+
+ // Runs some javascript within the context of a frame in the page.
+ void ExecuteJavascriptInWebFrame(const std::wstring& frame_xpath,
+ const std::wstring& jscript);
+
+ // Logs a message to the console of a frame in the page.
+ void AddMessageToConsole(const std::wstring& frame_xpath,
+ const std::wstring& msg,
+ ConsoleMessageLevel level);
+
+ // Send command to the debugger
+ void DebugCommand(const std::wstring& cmd);
+
+ // Attach to the V8 instance for debugging
+ void DebugAttach();
+
+ // Detach from the V8 instance for debugging
+ void DebugDetach();
+
+ // Cause the V8 debugger to trigger a debug break. If the force flag is set
+ // force a debug break even if no JS code is running (this actually causes a
+ // simple JS script to be executed).
+ void DebugBreak(bool force);
+
+ // Edit operations.
+ void Undo();
+ void Redo();
+ void Cut();
+ void Copy();
+ void Paste();
+ void Replace(const std::wstring& text);
+ void ToggleSpellCheck();
+ void AddToDictionary(const std::wstring& word);
+ void Delete();
+ void SelectAll();
+
+ // Downloads an image notifying the delegate appropriately. The returned
+ // integer uniquely identifies the download for the lifetime of the browser.
+ int DownloadImage(const GURL& url, int image_size);
+
+ // Requests application info for the specified page. This is an asynchronous
+ // request. The delegate is notified by way of OnDidGetApplicationInfo when
+ // the data is available.
+ void GetApplicationInfo(int32 page_id);
+
+ // Captures a thumbnail representation of the page.
+ void CaptureThumbnail();
+
+ // Notifies the RenderView that the JavaScript message that was shown was
+ // closed by the user.
+ void JavaScriptMessageBoxClosed(IPC::Message* reply_msg,
+ bool success,
+ const std::wstring& prompt);
+
+ // Notifies the RenderView that the modal html dialog has been closed.
+ void ModalHTMLDialogClosed(IPC::Message* reply_msg,
+ const std::string& json_retval);
+
+ // Copies the image at the specified point.
+ void CopyImageAt(int x, int y);
+
+ // Inspects the element at the specified point using the Web Inspector.
+ void InspectElementAt(int x, int y);
+
+ // Show the JavaScript console.
+ void ShowJavaScriptConsole();
+
+ // Notifies the renderer that a drop occurred. This is necessary because the
+ // render may be the one that started the drag.
+ void DragSourceEndedAt(
+ int client_x, int client_y, int screen_x, int screen_y);
+
+ // Notifies the renderer that a drag and drop operation is in progress, with
+ // droppable items positioned over the renderer's view.
+ void DragSourceMovedTo(
+ int client_x, int client_y, int screen_x, int screen_y);
+
+ // Notifies the renderer that we're done with the drag and drop operation.
+ // This allows the renderer to reset some state.
+ void DragSourceSystemDragEnded();
+
+ // Tell the render view to expose DOM automation bindings so that the js
+ // content can send JSON-encoded data back to automation in the parent
+ // process.
+ void AllowDomAutomationBindings();
+
+ // Tell the render view to allow the javascript access to
+ // the external host via automation.
+ void AllowExternalHostBindings();
+
+ // Tell the render view to expose DOM bindings so that the JS content
+ // can send JSON-encoded data back to the browser process.
+ // This is used for HTML-based UI.
+ // Must be called before CreateRenderView().
+ void AllowDOMUIBindings();
+
+ // Sets a property with the given name and value on the DOM UI binding object.
+ // Must call AllowDOMUIBindings() on this renderer first.
+ void SetDOMUIProperty(const std::string& name, const std::string& value);
+
+ // Fill in a ViewMsg_Navigate_Params struct from a NavigationEntry.
+ static void MakeNavigateParams(const NavigationEntry& entry,
+ bool reload,
+ ViewMsg_Navigate_Params* params);
+
+ // Overridden from RenderWidgetHost: We are hosting a web page.
+ virtual bool IsRenderView() { return true; }
+ virtual bool CanBlur() const;
+
+ // IPC::Channel::Listener
+ virtual void OnMessageReceived(const IPC::Message& msg);
+
+ // Override the RenderWidgetHost's Shutdown method.
+ virtual void Shutdown();
+
+ // Tells the renderer view to focus the first (last if reverse is true) node.
+ void SetInitialFocus(bool reverse);
+
+ // Update render view specific (WebKit) preferences.
+ void UpdateWebPreferences(const WebPreferences& prefs);
+
+ // Request the Renderer to ask the default plugin to start installation of
+ // missing plugin. Called by PluginInstaller.
+ void InstallMissingPlugin();
+
+ // Get all savable resource links from current webpage, include main
+ // frame and sub-frame.
+ void GetAllSavableResourceLinksForCurrentPage(const GURL& page_url);
+
+ // Get html data by serializing all frames of current page with lists
+ // which contain all resource links that have local copy.
+ // The parameter links contain original URLs of all saved links.
+ // The parameter local_paths contain corresponding local file paths of
+ // all saved links, which matched with vector:links one by one.
+ // The parameter local_directory_name is relative path of directory which
+ // contain all saved auxiliary files included all sub frames and resouces.
+ void GetSerializedHtmlDataForCurrentPageWithLocalLinks(
+ const std::vector<std::wstring>& links,
+ const std::vector<std::wstring>& local_paths,
+ const std::wstring& local_directory_name);
+
+ // Notifies the RenderViewHost that a file has been chosen by the user from
+ // an Open File dialog for the form.
+ void FileSelected(const std::wstring& path);
+
+ // Notifies the Listener that many files have been chosen by the user from
+ // an Open File dialog for the form.
+ void MultiFilesSelected(const std::vector<std::wstring>& files);
+
+ // Notifies the RenderViewHost that its load state changed.
+ void LoadStateChanged(const GURL& url, net::LoadState load_state);
+
+ // Does the associated view have an onunload or onbeforeunload handler?
+ bool HasUnloadListener() { return has_unload_listener_; }
+
+ // If the associated view can be terminated without any side effects
+ bool CanTerminate() const;
+
+ // Clears the has_unload_listener_ bit since the unload handler has fired
+ // and we're necessarily leaving the page.
+ void UnloadListenerHasFired() { has_unload_listener_ = false; }
+
+#ifdef CHROME_PERSONALIZATION
+ // Tells the RenderView to raise an personalization event with the given name
+ // and argument.
+ void RaisePersonalizationEvent(std::string event_name, std::string event_arg);
+
+ HostPersonalization personalization() {
+ return personalization_;
+ }
+#endif
+
+ // Forward a message from external host to chrome renderer.
+ void ForwardMessageFromExternalHost(const std::string& target,
+ const std::string& message);
+
+ // Message the renderer that we should be counted as a new document and not
+ // as a popup.
+ void DisassociateFromPopupCount();
+
+ // Notifies the Renderer that we've either displayed or hidden the popup
+ // notification.
+ void PopupNotificationVisibilityChanged(bool visible);
+
+ // Called by the AutofillManager when the list of suggestions is ready.
+ void AutofillSuggestionsReturned(const std::vector<std::wstring>& suggestions,
+ int64 node_id,
+ int request_id,
+ int default_suggestion_index);
+
+ protected:
+ // Overridden from RenderWidgetHost:
+ virtual void UnhandledInputEvent(const WebInputEvent& event);
+ virtual void ForwardKeyboardEvent(const WebKeyboardEvent& key_event);
+
+ // IPC message handlers:
+ void OnMsgCreateWindow(int route_id, HANDLE modal_dialog_event);
+ void OnMsgCreateWidget(int route_id, bool activatable);
+ void OnMsgShowView(int route_id,
+ WindowOpenDisposition disposition,
+ const gfx::Rect& initial_pos,
+ bool user_gesture);
+ void OnMsgShowWidget(int route_id, const gfx::Rect& initial_pos);
+ void OnMsgRunModal(IPC::Message* reply_msg);
+ void OnMsgRendererReady();
+ void OnMsgRendererGone();
+ void OnMsgNavigate(const IPC::Message& msg);
+ void OnMsgUpdateState(int32 page_id,
+ const std::string& state);
+ void OnMsgUpdateTitle(int32 page_id, const std::wstring& title);
+ void OnMsgUpdateEncoding(const std::wstring& encoding);
+ void OnMsgUpdateTargetURL(int32 page_id, const GURL& url);
+ void OnMsgThumbnail(const IPC::Message& msg);
+ void OnMsgClose();
+ void OnMsgRequestMove(const gfx::Rect& pos);
+ void OnMsgDidRedirectProvisionalLoad(int32 page_id,
+ const GURL& source_url,
+ const GURL& target_url);
+ void OnMsgDidStartLoading(int32 page_id);
+ void OnMsgDidStopLoading(int32 page_id);
+ void OnMsgDidLoadResourceFromMemoryCache(const GURL& url,
+ const std::string& security_info);
+ void OnMsgDidStartProvisionalLoadForFrame(bool main_frame,
+ const GURL& url);
+ void OnMsgDidFailProvisionalLoadWithError(bool main_frame,
+ int error_code,
+ const GURL& url,
+ bool showing_repost_interstitial);
+ void OnMsgFindReply(int request_id,
+ int number_of_matches,
+ const gfx::Rect& selection_rect,
+ int active_match_ordinal,
+ bool final_update);
+ void OnMsgUpdateFavIconURL(int32 page_id, const GURL& icon_url);
+ void OnMsgDidDownloadImage(int id,
+ const GURL& image_url,
+ bool errored,
+ const SkBitmap& image_data);
+ void OnMsgContextMenu(const ViewHostMsg_ContextMenu_Params& params);
+ void OnMsgOpenURL(const GURL& url, const GURL& referrer,
+ WindowOpenDisposition disposition);
+ void OnMsgDomOperationResponse(const std::string& json_string,
+ int automation_id);
+ void OnMsgDOMUISend(const std::string& message,
+ const std::string& content);
+ void OnMsgForwardMessageToExternalHost(const std::string& receiver,
+ const std::string& message);
+#ifdef CHROME_PERSONALIZATION
+ void OnPersonalizationEvent(const std::string& message,
+ const std::string& content);
+#endif
+ void OnMsgGoToEntryAtOffset(int offset);
+ void OnMsgSetTooltipText(const std::wstring& tooltip_text);
+ void OnMsgRunFileChooser(bool multiple_files,
+ const std::wstring& title,
+ const std::wstring& default_file,
+ const std::wstring& filter);
+ void OnMsgRunJavaScriptMessage(const std::wstring& message,
+ const std::wstring& default_prompt,
+ const int flags,
+ IPC::Message* reply_msg);
+ void OnMsgRunBeforeUnloadConfirm(const std::wstring& message,
+ IPC::Message* reply_msg);
+ void OnMsgShowModalHTMLDialog(const GURL& url, int width, int height,
+ const std::string& json_arguments,
+ IPC::Message* reply_msg);
+ void OnMsgPasswordFormsSeen(const std::vector<PasswordForm>& forms);
+ void OnMsgAutofillFormSubmitted(const AutofillForm& forms);
+ void OnMsgStartDragging(const WebDropData& drop_data);
+ void OnUpdateDragCursor(bool is_drop_target);
+ void OnTakeFocus(bool reverse);
+ void OnMsgPageHasOSDD(int32 page_id, const GURL& doc_url, bool autodetected);
+ void OnMsgInspectElementReply(int num_resources);
+ void DidPrintPage(const ViewHostMsg_DidPrintPage_Params& params);
+ void OnDebugMessage(const std::string& message);
+ void OnAddMessageToConsole(const std::wstring& message,
+ int32 line_no,
+ const std::wstring& source_id);
+ void OnDebuggerOutput(const std::wstring& output);
+ void DidDebugAttach();
+ void OnUserMetricsRecordAction(const std::wstring& action);
+ void OnMissingPluginStatus(int status);
+ void OnMessageReceived(IPC::Message* msg) { }
+
+ void OnReceivedSavableResourceLinksForCurrentPage(
+ const std::vector<GURL>& resources_list,
+ const std::vector<GURL>& referrers_list,
+ const std::vector<GURL>& frames_list);
+
+ void OnReceivedSerializedHtmlData(const GURL& frame_url,
+ const std::string& data,
+ int32 status);
+
+ void OnDidGetApplicationInfo(int32 page_id,
+ const webkit_glue::WebApplicationInfo& info);
+ void OnMsgShouldCloseACK(bool proceed);
+ void OnUnloadListenerChanged(bool has_handler);
+ void OnQueryFormFieldAutofill(const std::wstring& field_name,
+ const std::wstring& user_text,
+ int64 node_id,
+ int request_id);
+ virtual void NotifyRendererUnresponsive();
+ virtual void NotifyRendererResponsive();
+
+ // Helper function to send a navigation message. If a cross-site request is
+ // in progress, we may be suspended while waiting for the onbeforeunload
+ // handler, so this function might buffer the message rather than sending it.
+ void DoNavigate(ViewMsg_Navigate* nav_message);
+
+ private:
+ friend class TestRenderViewHost;
+
+ void UpdateBackForwardListCount();
+
+ void OnDebugDisconnect();
+
+ // The SiteInstance associated with this RenderViewHost. All pages drawn
+ // in this RenderViewHost are part of this SiteInstance. Should not change
+ // over time.
+ scoped_refptr<SiteInstance> instance_;
+
+ // Our delegate, which wants to know about changes in the RenderView.
+ RenderViewHostDelegate* delegate_;
+
+#ifdef CHROME_PERSONALIZATION
+ HostPersonalization personalization_;
+#endif
+
+ // true if a renderer has once been valid. We use this flag to display a sad
+ // tab only when we lose our renderer and not if a paint occurs during
+ // initialization.
+ bool renderer_initialized_;
+
+ // true if we are currently waiting for a response for drag context
+ // information.
+ bool waiting_for_drag_context_response_;
+
+ // is the debugger attached to us or not
+ bool debugger_attached_;
+
+ // True if we've been told to set up the the Javascript bindings for
+ // sending messages back to the browser.
+ bool enable_dom_ui_bindings_;
+
+ // The request_id for the pending cross-site request. Set to -1 if
+ // there is a pending request, but we have not yet started the unload
+ // for the current page. Set to the request_id value of the pending
+ // request once we have gotten the some data for the pending page
+ // and thus started the unload process.
+ int pending_request_id_;
+
+ // True if javascript access to the external host (through
+ // automation) is allowed.
+ bool enable_external_host_bindings_;
+
+ // Handle to an event that's set when the page is showing a modal dialog box
+ // (or equivalent constrained window). The renderer and plugin processes
+ // check this to know if they should pump messages/tasks then.
+ scoped_ptr<base::WaitableEvent> modal_dialog_event_;
+
+ // Multiple dialog boxes can be shown before the first one is finished,
+ // so we keep a counter to know when we can reset the modal dialog event.
+ int modal_dialog_count_;
+
+ // Whether we should buffer outgoing Navigate messages rather than sending
+ // them. This will be true when a RenderViewHost is created for a cross-site
+ // request, until we hear back from the onbeforeunload handler of the old
+ // RenderViewHost.
+ bool navigations_suspended_;
+
+ // We only buffer a suspended navigation message while we a pending RVH for a
+ // WebContents. There will only ever be one suspended navigation, because
+ // WebContents will destroy the pending RVH and create a new one if a second
+ // navigation occurs.
+ scoped_ptr<ViewMsg_Navigate> suspended_nav_message_;
+
+ // If we were asked to RunModal, then this will hold the reply_msg that we
+ // must return to the renderer to unblock it.
+ IPC::Message* run_modal_reply_msg_;
+
+ bool has_unload_listener_;
+
+ bool is_waiting_for_unload_ack_;
+
+ bool are_javascript_messages_suppressed_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(RenderViewHost);
+};
+
+// Factory for creating RenderViewHosts. Useful for unit tests.
+class RenderViewHostFactory {
+ public:
+ virtual ~RenderViewHostFactory() {}
+
+ virtual RenderViewHost* CreateRenderViewHost(
+ SiteInstance* instance,
+ RenderViewHostDelegate* delegate,
+ int routing_id,
+ base::WaitableEvent* modal_dialog_event) = 0;
+};
+
+#endif // CHROME_BROWSER_RENDER_VIEW_HOST_H__
diff --git a/chrome/browser/renderer_host/render_view_host_delegate.h b/chrome/browser/renderer_host/render_view_host_delegate.h
new file mode 100644
index 0000000..764e8ca
--- /dev/null
+++ b/chrome/browser/renderer_host/render_view_host_delegate.h
@@ -0,0 +1,396 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_RENDERER_HOST_RENDER_VIEW_HOST_DELEGATE_H_
+#define CHROME_BROWSER_RENDERER_HOST_RENDER_VIEW_HOST_DELEGATE_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "chrome/browser/autofill_manager.h"
+#include "chrome/common/render_messages.h"
+#include "webkit/glue/webpreferences.h"
+
+class NavigationEntry;
+class Profile;
+class RenderProcessHost;
+class RenderViewHost;
+class SkBitmap;
+class WebContents;
+struct WebDropData;
+enum WindowOpenDisposition;
+
+namespace base {
+class WaitableEvent;
+}
+
+namespace IPC {
+class Message;
+}
+
+namespace gfx {
+class Rect;
+}
+
+namespace net {
+enum LoadState;
+}
+
+//
+// RenderViewHostDelegate
+//
+// An interface implemented by an object interested in knowing about the state
+// of the RenderViewHost.
+//
+// This interface currently encompasses every type of message that was
+// previously being sent by WebContents itself. Some of these notifications
+// may not be relevant to all users of RenderViewHost and we should consider
+// exposing a more generic Send function on RenderViewHost and a response
+// listener here to serve that need.
+//
+class RenderViewHostDelegate {
+ public:
+ class View {
+ public:
+ // The page is trying to open a new page (e.g. a popup window). The
+ // window should be created associated with the given route, but it should
+ // not be shown yet. That should happen in response to ShowCreatedWindow.
+ //
+ // Note: this is not called "CreateWindow" because that will clash with
+ // the Windows function which is actually a #define.
+ //
+ // NOTE: this takes ownership of @modal_dialog_event
+ virtual void CreateNewWindow(int route_id,
+ base::WaitableEvent* modal_dialog_event) = 0;
+
+ // The page is trying to open a new widget (e.g. a select popup). The
+ // widget should be created associated with the given route, but it should
+ // not be shown yet. That should happen in response to ShowCreatedWidget.
+ // If |activatable| is false, the widget cannot be activated or get focus.
+ virtual void CreateNewWidget(int route_id, bool activatable) = 0;
+
+ // Show a previously created page with the specified disposition and bounds.
+ // The window is identified by the route_id passed to CreateNewWindow.
+ //
+ // Note: this is not called "ShowWindow" because that will clash with
+ // the Windows function which is actually a #define.
+ virtual void ShowCreatedWindow(int route_id,
+ WindowOpenDisposition disposition,
+ const gfx::Rect& initial_pos,
+ bool user_gesture) = 0;
+
+ // Show the newly created widget with the specified bounds.
+ // The widget is identified by the route_id passed to CreateNewWidget.
+ virtual void ShowCreatedWidget(int route_id,
+ const gfx::Rect& initial_pos) = 0;
+
+ // A context menu should be shown, to be built using the context information
+ // provided in the supplied params.
+ virtual void ShowContextMenu(
+ const ViewHostMsg_ContextMenu_Params& params) = 0;
+
+ // The user started dragging content of the specified type within the
+ // RenderView. Contextual information about the dragged content is supplied
+ // by WebDropData.
+ virtual void StartDragging(const WebDropData& drop_data) = 0;
+
+ // The page wants to update the mouse cursor during a drag & drop operation.
+ // |is_drop_target| is true if the mouse is over a valid drop target.
+ virtual void UpdateDragCursor(bool is_drop_target) = 0;
+
+ // Callback to inform the browser it should take back focus. If reverse is
+ // true, it means the focus was retrieved by doing a Shift-Tab.
+ virtual void TakeFocus(bool reverse) = 0;
+
+ // Callback to inform the browser that the renderer did not process the
+ // specified events. This gives an opportunity to the browser to process the
+ // event (used for keyboard shortcuts).
+ virtual void HandleKeyboardEvent(const WebKeyboardEvent& event) = 0;
+
+ // A find operation in the current page completed.
+ virtual void OnFindReply(int request_id,
+ int number_of_matches,
+ const gfx::Rect& selection_rect,
+ int active_match_ordinal,
+ bool final_update) = 0;
+ };
+
+ // Interface for saving web pages.
+ class Save {
+ public:
+ // Notification that we get when we receive all savable links of
+ // sub-resources for the current page, their referrers and list of frames
+ // (include main frame and sub frames).
+ virtual void OnReceivedSavableResourceLinksForCurrentPage(
+ const std::vector<GURL>& resources_list,
+ const std::vector<GURL>& referrers_list,
+ const std::vector<GURL>& frames_list) = 0;
+
+ // Notification that we get when we receive serialized html content data of
+ // a specified web page from render process. The parameter frame_url
+ // specifies what frame the data belongs. The parameter data contains the
+ // available data for sending. The parameter status indicates the
+ // serialization status, See
+ // webkit_glue::DomSerializerDelegate::PageSavingSerializationStatus for
+ // the detail meaning of status.
+ virtual void OnReceivedSerializedHtmlData(const GURL& frame_url,
+ const std::string& data,
+ int32 status) = 0;
+ };
+
+ // Returns the current delegate associated with a feature. May be NULL.
+ virtual View* GetViewDelegate() const { return NULL; }
+ virtual Save* GetSaveDelegate() const { return NULL; }
+
+ // Retrieves the profile to be used.
+ virtual Profile* GetProfile() const = 0;
+
+ // The RenderView is being constructed (message sent to the renderer process
+ // to construct a RenderView). Now is a good time to send other setup events
+ // to the RenderView. This precedes any other commands to the RenderView.
+ virtual void RendererCreated(RenderViewHost* render_view_host) { }
+
+ // The RenderView has been constructed.
+ virtual void RendererReady(RenderViewHost* render_view_host) { }
+
+ // The RenderView died somehow (crashed or was killed by the user).
+ virtual void RendererGone(RenderViewHost* render_view_host) { }
+
+ // The RenderView was navigated to a different page.
+ virtual void DidNavigate(RenderViewHost* render_view_host,
+ const ViewHostMsg_FrameNavigate_Params& params) { }
+
+ // The state for the page changed and should be updated.
+ virtual void UpdateState(RenderViewHost* render_view_host,
+ int32 page_id,
+ const std::string& state) { }
+
+ // The page's title was changed and should be updated.
+ virtual void UpdateTitle(RenderViewHost* render_view_host,
+ int32 page_id,
+ const std::wstring& title) { }
+
+ // The page's encoding was changed and should be updated.
+ virtual void UpdateEncoding(RenderViewHost* render_view_host,
+ const std::wstring& encoding) { }
+
+ // The destination URL has changed should be updated
+ virtual void UpdateTargetURL(int32 page_id, const GURL& url) { }
+
+ // The thumbnail representation of the page changed and should be updated.
+ virtual void UpdateThumbnail(const GURL& url,
+ const SkBitmap& bitmap,
+ const ThumbnailScore& score) { }
+
+ // The page is trying to close the RenderView's representation in the client.
+ virtual void Close(RenderViewHost* render_view_host) { }
+
+ // The page is trying to move the RenderView's representation in the client.
+ virtual void RequestMove(const gfx::Rect& new_bounds) { }
+
+ // The RenderView began loading a new page.
+ virtual void DidStartLoading(RenderViewHost* render_view_host,
+ int32 page_id) { }
+
+ // The RenderView stopped loading a page.
+ virtual void DidStopLoading(RenderViewHost* render_view_host,
+ int32 page_id) { }
+
+ // The RenderView is starting a provisional load.
+ virtual void DidStartProvisionalLoadForFrame(RenderViewHost* render_view_host,
+ bool is_main_frame,
+ const GURL& url) { }
+
+ // Sent when a provisional load is redirected.
+ virtual void DidRedirectProvisionalLoad(int32 page_id,
+ const GURL& source_url,
+ const GURL& target_url) { }
+
+ // The RenderView loaded a resource from an in-memory cache.
+ // |security_info| contains the security info if this resource was originally
+ // loaded over a secure connection.
+ virtual void DidLoadResourceFromMemoryCache(const GURL& url,
+ const std::string& security_info) { }
+
+ // The RenderView failed a provisional load with an error.
+ virtual void DidFailProvisionalLoadWithError(
+ RenderViewHost* render_view_host,
+ bool is_main_frame,
+ int error_code,
+ const GURL& url,
+ bool showing_repost_interstitial) { }
+
+ // The URL for the FavIcon of a page has changed.
+ virtual void UpdateFavIconURL(RenderViewHost* render_view_host,
+ int32 page_id, const GURL& icon_url) { }
+
+ // An image that was requested to be downloaded by DownloadImage has
+ // completed.
+ virtual void DidDownloadImage(RenderViewHost* render_view_host,
+ int id,
+ const GURL& image_url,
+ bool errored,
+ const SkBitmap& image) { }
+
+ // The page wants to open a URL with the specified disposition.
+ virtual void RequestOpenURL(const GURL& url,
+ const GURL& referrer,
+ WindowOpenDisposition disposition) { }
+
+ // A DOM automation operation completed. The result of the operation is
+ // expressed in a json string.
+ virtual void DomOperationResponse(const std::string& json_string,
+ int automation_id) { }
+
+ // A message was sent from HTML-based UI.
+ // By default we ignore such messages.
+ virtual void ProcessDOMUIMessage(const std::string& message,
+ const std::string& content) { }
+
+ // A message for external host. By default we ignore such messages.
+ // |receiver| can be a receiving script and |message| is any
+ // arbitrary string that makes sense to the receiver.
+ virtual void ProcessExternalHostMessage(const std::string& receiver,
+ const std::string& message) { }
+
+ // Navigate to the history entry for the given offset from the current
+ // position within the NavigationController. Makes no change if offset is
+ // not valid.
+ virtual void GoToEntryAtOffset(int offset) { }
+
+ // The page requests the size of the back and forward lists
+ // within the NavigationController.
+ virtual void GetHistoryListCount(int* back_list_count,
+ int* forward_list_count) { }
+
+ // A file chooser should be shown.
+ virtual void RunFileChooser(bool multiple_files,
+ const std::wstring& title,
+ const std::wstring& default_file,
+ const std::wstring& filter) { }
+
+ // A javascript message, confirmation or prompt should be shown.
+ virtual void RunJavaScriptMessage(const std::wstring& message,
+ const std::wstring& default_prompt,
+ const int flags,
+ IPC::Message* reply_msg,
+ bool* did_suppress_message) { }
+
+ virtual void RunBeforeUnloadConfirm(const std::wstring& message,
+ IPC::Message* reply_msg) { }
+
+ // Display this RenderViewHost in a modal fashion.
+ virtual void RunModal(IPC::Message* reply_msg) { }
+
+ virtual void ShowModalHTMLDialog(const GURL& url, int width, int height,
+ const std::string& json_arguments,
+ IPC::Message* reply_msg) { }
+
+ // Password forms have been detected in the page.
+ virtual void PasswordFormsSeen(const std::vector<PasswordForm>& forms) { }
+
+ // Forms fillable by autofill have been detected in the page.
+ virtual void AutofillFormSubmitted(const AutofillForm& form) { }
+
+ // Called to retrieve a list of suggestions from the web database given
+ // the name of the field |field_name| and what the user has already typed in
+ // the field |user_text|. Appeals to the database thead to perform the query.
+ // When the database thread is finished, the autofill manager retrieves the
+ // calling RenderViewHost and then passes the vector of suggestions to
+ // RenderViewHost::AutofillSuggestionsReturned.
+ virtual void GetAutofillSuggestions(const std::wstring& field_name,
+ const std::wstring& user_text,
+ int64 node_id,
+ int request_id) { }
+
+ // Notification that the page has an OpenSearch description document.
+ virtual void PageHasOSDD(RenderViewHost* render_view_host,
+ int32 page_id, const GURL& doc_url,
+ bool autodetected) { }
+
+ // Notification that the inspect element window has been opened
+ virtual void InspectElementReply(int num_resources) { }
+
+ // Notification that the render view has calculated the number of printed
+ // pages.
+ virtual void DidGetPrintedPagesCount(int cookie, int number_pages) {
+ NOTREACHED();
+ }
+
+ // Notification that the render view is done rendering one printed page. This
+ // call is synchronous, the renderer is waiting on us because of the EMF
+ // memory mapped data.
+ virtual void DidPrintPage(const ViewHostMsg_DidPrintPage_Params& params) {
+ NOTREACHED();
+ }
+
+ // |url| is assigned to a server that can provide alternate error pages. If
+ // unchanged, just use the error pages built into our webkit.
+ virtual GURL GetAlternateErrorPageURL() const {
+ return GURL();
+ }
+
+ // Returns a WebPreferences object that will be used by the renderer
+ // associated with the owning render view host.
+ virtual WebPreferences GetWebkitPrefs() {
+ NOTREACHED();
+ return WebPreferences();
+ }
+
+ // Notification when default plugin updates status of the missing plugin.
+ virtual void OnMissingPluginStatus(int status) { }
+
+ // Notification from the renderer that a plugin instance has crashed.
+ virtual void OnCrashedPlugin(const FilePath& plugin_path) { }
+
+ // Notification from the renderer that JS runs out of memory.
+ virtual void OnJSOutOfMemory() { }
+
+ // Notification whether we should close the page, after an explicit call to
+ // AttemptToClosePage. This is called before a cross-site request or before
+ // a tab/window is closed, to allow the appropriate renderer to approve or
+ // deny the request. |proceed| indicates whether the user chose to proceed.
+ virtual void ShouldClosePage(bool proceed) { }
+
+ // Called by ResourceDispatcherHost when a response for a pending cross-site
+ // request is received. The ResourceDispatcherHost will pause the response
+ // until the onunload handler of the previous renderer is run.
+ virtual void OnCrossSiteResponse(int new_render_process_host_id,
+ int new_request_id) { }
+
+ // Whether this object can be blurred through a javascript
+ // obj.blur() call. ConstrainedWindows shouldn't be able to be
+ // blurred.
+ virtual bool CanBlur() const { return true; }
+
+ // Notification that the renderer has become unresponsive. The
+ // delegate can use this notification to show a warning to the user.
+ virtual void RendererUnresponsive(RenderViewHost* render_view_host,
+ bool is_during_unload) { }
+
+ // Notification that a previously unresponsive renderer has become
+ // responsive again. The delegate can use this notification to end the
+ // warning shown to the user.
+ virtual void RendererResponsive(RenderViewHost* render_view_host) { }
+
+ // Notification that the RenderViewHost's load state changed.
+ virtual void LoadStateChanged(const GURL& url, net::LoadState load_state) { }
+
+ // Notification that a request for install info has completed.
+ virtual void OnDidGetApplicationInfo(
+ int32 page_id,
+ const webkit_glue::WebApplicationInfo& app_info) { }
+
+ // Notification the user has pressed enter or space while focus was on the
+ // page. This is used to avoid uninitiated user downloads (aka carpet
+ // bombing), see DownloadRequestManager for details.
+ virtual void OnEnterOrSpace() { }
+
+ // If this view can be terminated without any side effects
+ virtual bool CanTerminate() const { return true; }
+};
+
+#endif // CHROME_BROWSER_RENDERER_HOST_RENDER_VIEW_HOST_DELEGATE_H_
+
diff --git a/chrome/browser/renderer_host/render_widget_helper.cc b/chrome/browser/renderer_host/render_widget_helper.cc
new file mode 100644
index 0000000..8d85d92
--- /dev/null
+++ b/chrome/browser/renderer_host/render_widget_helper.cc
@@ -0,0 +1,235 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/renderer_host/render_widget_helper.h"
+
+#include "base/thread.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/renderer_host/render_process_host.h"
+#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
+
+using base::TimeDelta;
+using base::TimeTicks;
+
+// A Task used with InvokeLater that we hold a pointer to in pending_paints_.
+// Instances are deleted by MessageLoop after it calls their Run method.
+class RenderWidgetHelper::PaintMsgProxy : public Task {
+ public:
+ explicit PaintMsgProxy(RenderWidgetHelper* h, const IPC::Message& m)
+ : helper(h),
+ message(m),
+ cancelled(false) {
+ }
+
+ ~PaintMsgProxy() {
+ // If the paint message was never dispatched, then we need to let the
+ // helper know that we are going away.
+ if (!cancelled && helper)
+ helper->OnDiscardPaintMsg(this);
+ }
+
+ virtual void Run() {
+ if (!cancelled) {
+ helper->OnDispatchPaintMsg(this);
+ helper = NULL;
+ }
+ }
+
+ scoped_refptr<RenderWidgetHelper> helper;
+ IPC::Message message;
+ bool cancelled; // If true, then the message will not be dispatched.
+
+ DISALLOW_EVIL_CONSTRUCTORS(PaintMsgProxy);
+};
+
+RenderWidgetHelper::RenderWidgetHelper(int render_process_id)
+ : render_process_id_(render_process_id),
+ ui_loop_(MessageLoop::current()),
+ event_(CreateEvent(NULL, FALSE /* auto-reset */, FALSE, NULL)),
+ block_popups_(false) {
+}
+
+RenderWidgetHelper::~RenderWidgetHelper() {
+ // The elements of pending_paints_ each hold an owning reference back to this
+ // object, so we should not be destroyed unless pending_paints_ is empty!
+ DCHECK(pending_paints_.empty());
+
+ CloseHandle(event_);
+}
+
+int RenderWidgetHelper::GetNextRoutingID() {
+ return next_routing_id_.GetNext() + 1;
+}
+
+void RenderWidgetHelper::CancelResourceRequests(int render_widget_id) {
+ if (g_browser_process->io_thread())
+ g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE,
+ NewRunnableMethod(this,
+ &RenderWidgetHelper::OnCancelResourceRequests,
+ g_browser_process->resource_dispatcher_host(),
+ render_widget_id));
+}
+
+void RenderWidgetHelper::CrossSiteClosePageACK(int new_render_process_host_id,
+ int new_request_id) {
+ if (g_browser_process->io_thread())
+ g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE,
+ NewRunnableMethod(this,
+ &RenderWidgetHelper::OnCrossSiteClosePageACK,
+ g_browser_process->resource_dispatcher_host(),
+ new_render_process_host_id,
+ new_request_id));
+}
+
+bool RenderWidgetHelper::WaitForPaintMsg(int render_widget_id,
+ const TimeDelta& max_delay,
+ IPC::Message* msg) {
+ TimeTicks time_start = TimeTicks::Now();
+
+ for (;;) {
+ PaintMsgProxy* proxy = NULL;
+ {
+ AutoLock lock(pending_paints_lock_);
+
+ PaintMsgProxyMap::iterator it = pending_paints_.find(render_widget_id);
+ if (it != pending_paints_.end()) {
+ proxy = it->second;
+
+ // Flag the proxy as cancelled so that when it is run as a task it will
+ // do nothing.
+ proxy->cancelled = true;
+
+ pending_paints_.erase(it);
+ }
+ }
+
+ if (proxy) {
+ *msg = proxy->message;
+ DCHECK(msg->routing_id() == render_widget_id);
+ return true;
+ }
+
+ // Calculate the maximum amount of time that we are willing to sleep.
+ TimeDelta max_sleep_time =
+ max_delay - (TimeTicks::Now() - time_start);
+ if (max_sleep_time <= TimeDelta::FromMilliseconds(0))
+ break;
+
+ WaitForSingleObject(event_,
+ static_cast<DWORD>(max_sleep_time.InMilliseconds()));
+ }
+
+ return false;
+}
+
+void RenderWidgetHelper::DidReceivePaintMsg(const IPC::Message& msg) {
+ int render_widget_id = msg.routing_id();
+
+ PaintMsgProxy* proxy;
+ {
+ AutoLock lock(pending_paints_lock_);
+
+ PaintMsgProxyMap::value_type new_value(render_widget_id, NULL);
+
+ // We expect only a single PaintRect message at a time. Optimize for the
+ // case that we don't already have an entry by using the 'insert' method.
+ std::pair<PaintMsgProxyMap::iterator, bool> result =
+ pending_paints_.insert(new_value);
+ if (!result.second) {
+ NOTREACHED() << "Unexpected PaintRect message!";
+ return;
+ }
+
+ result.first->second = (proxy = new PaintMsgProxy(this, msg));
+ }
+
+ // Notify anyone waiting on the UI thread that there is a new entry in the
+ // proxy map. If they don't find the entry they are looking for, then they
+ // will just continue waiting.
+ SetEvent(event_);
+
+ // The proxy will be deleted when it is run as a task.
+ ui_loop_->PostTask(FROM_HERE, proxy);
+}
+
+void RenderWidgetHelper::OnDiscardPaintMsg(PaintMsgProxy* proxy) {
+ const IPC::Message& msg = proxy->message;
+
+ // Remove the proxy from the map now that we are going to handle it normally.
+ {
+ AutoLock lock(pending_paints_lock_);
+
+ PaintMsgProxyMap::iterator it = pending_paints_.find(msg.routing_id());
+ DCHECK(it != pending_paints_.end());
+ DCHECK(it->second == proxy);
+
+ pending_paints_.erase(it);
+ }
+}
+
+void RenderWidgetHelper::OnDispatchPaintMsg(PaintMsgProxy* proxy) {
+ OnDiscardPaintMsg(proxy);
+
+ // It is reasonable for the host to no longer exist.
+ RenderProcessHost* host = RenderProcessHost::FromID(render_process_id_);
+ if (host)
+ host->OnMessageReceived(proxy->message);
+}
+
+void RenderWidgetHelper::OnCancelResourceRequests(
+ ResourceDispatcherHost* dispatcher,
+ int render_widget_id) {
+ dispatcher->CancelRequestsForRenderView(render_process_id_, render_widget_id);
+}
+
+void RenderWidgetHelper::OnCrossSiteClosePageACK(
+ ResourceDispatcherHost* dispatcher,
+ int new_render_process_host_id,
+ int new_request_id) {
+ dispatcher->OnClosePageACK(new_render_process_host_id, new_request_id);
+}
+
+void RenderWidgetHelper::CreateNewWindow(int opener_id,
+ bool user_gesture,
+ int* route_id,
+ HANDLE* modal_dialog_event,
+ HANDLE render_process) {
+ if (!user_gesture && block_popups_) {
+ *route_id = MSG_ROUTING_NONE;
+ *modal_dialog_event = NULL;
+ return;
+ }
+
+ *route_id = GetNextRoutingID();
+ HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL);
+ BOOL result = DuplicateHandle(GetCurrentProcess(),
+ event,
+ render_process,
+ modal_dialog_event,
+ SYNCHRONIZE,
+ FALSE,
+ 0);
+ DCHECK(result) << "Couldn't duplicate modal dialog event for the renderer.";
+
+ // The easiest way to reach RenderViewHost is just to send a routed message.
+ ViewHostMsg_CreateWindowWithRoute msg(opener_id, *route_id, event);
+ ui_loop_->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &RenderWidgetHelper::OnSimulateReceivedMessage, msg));
+}
+
+void RenderWidgetHelper::CreateNewWidget(int opener_id,
+ bool activatable,
+ int* route_id) {
+ *route_id = GetNextRoutingID();
+ ViewHostMsg_CreateWidgetWithRoute msg(opener_id, *route_id, activatable);
+ ui_loop_->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &RenderWidgetHelper::OnSimulateReceivedMessage, msg));
+}
+
+void RenderWidgetHelper::OnSimulateReceivedMessage(
+ const IPC::Message& message) {
+ RenderProcessHost* host = RenderProcessHost::FromID(render_process_id_);
+ if (host)
+ host->OnMessageReceived(message);
+}
diff --git a/chrome/browser/renderer_host/render_widget_helper.h b/chrome/browser/renderer_host/render_widget_helper.h
new file mode 100644
index 0000000..aca3644
--- /dev/null
+++ b/chrome/browser/renderer_host/render_widget_helper.h
@@ -0,0 +1,159 @@
+
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_RENDEDER_HOST_RENDER_WIDGET_HELPER_H_
+#define CHROME_BROWSER_RENDEDER_HOST_RENDER_WIDGET_HELPER_H_
+
+#include "base/atomic_sequence_num.h"
+#include "base/hash_tables.h"
+#include "base/ref_counted.h"
+#include "base/lock.h"
+
+namespace IPC {
+class Message;
+}
+
+namespace base {
+class TimeDelta;
+}
+
+class MessageLoop;
+class ResourceDispatcherHost;
+
+// Instantiated per RenderProcessHost to provide various optimizations on
+// behalf of a RenderWidgetHost. This class bridges between the IO thread
+// where the RenderProcessHost's MessageFilter lives and the UI thread where
+// the RenderWidgetHost lives.
+//
+//
+// OPTIMIZED RESIZE
+//
+// RenderWidgetHelper is used to implement optimized resize. When the
+// RenderWidgetHost is resized, it sends a Resize message to its RenderWidget
+// counterpart in the renderer process. The RenderWidget generates a
+// PaintRect message in response to the Resize message, and it sets the
+// IS_RESIZE_ACK flag in the PaintRect message to true.
+//
+// Back in the browser process, when the RenderProcessHost's MessageFilter
+// sees a PaintRect message, it directs it to the RenderWidgetHelper by
+// calling the DidReceivePaintMsg method. That method stores the data for
+// the PaintRect message in a map, where it can be directly accessed by the
+// RenderWidgetHost on the UI thread during a call to RenderWidgetHost's
+// GetBackingStore method.
+//
+// When the RenderWidgetHost's GetBackingStore method is called, it first
+// checks to see if it is waiting for a resize ack. If it is, then it calls
+// the RenderWidgetHelper's WaitForPaintMsg to check if there is already a
+// resulting PaintRect message (or to wait a short amount of time for one to
+// arrive). The main goal of this mechanism is to short-cut the usual way in
+// which IPC messages are proxied over to the UI thread via InvokeLater.
+// This approach is necessary since window resize is followed up immediately
+// by a request to repaint the window.
+//
+//
+// OPTIMIZED TAB SWITCHING
+//
+// When a RenderWidgetHost is in a background tab, it is flagged as hidden.
+// This causes the corresponding RenderWidget to stop sending PaintRect
+// messages. The RenderWidgetHost also discards its backingstore when it is
+// hidden, which helps free up memory. As a result, when a RenderWidgetHost
+// is restored, it can be momentarily without a backingstore. (Restoring a
+// RenderWidgetHost results in a WasRestored message being sent to the
+// RenderWidget, which triggers a full PaintRect message.) This can lead to
+// an observed rendering glitch as the WebContents will just have to fill
+// white overtop the RenderWidgetHost until the RenderWidgetHost receives a
+// PaintRect message to refresh its backingstore.
+//
+// To avoid this 'white flash', the RenderWidgetHost again makes use of the
+// RenderWidgetHelper's WaitForPaintMsg method. When the RenderWidgetHost's
+// GetBackingStore method is called, it will call WaitForPaintMsg if it has
+// no backingstore.
+//
+class RenderWidgetHelper :
+ public base::RefCountedThreadSafe<RenderWidgetHelper> {
+ public:
+ RenderWidgetHelper(int render_process_id);
+ ~RenderWidgetHelper();
+
+ // Gets the next available routing id. This is thread safe.
+ int GetNextRoutingID();
+
+ // Sets whether popup blocking is enabled or not.
+ void set_block_popups(bool block) { block_popups_ = block; }
+
+
+ // UI THREAD ONLY -----------------------------------------------------------
+
+ // These three functions provide the backend implementation of the
+ // corresponding functions in RenderProcessHost. See those declarations
+ // for documentation.
+ void CancelResourceRequests(int render_widget_id);
+ void CrossSiteClosePageACK(int new_render_process_host_id,
+ int new_request_id);
+ bool WaitForPaintMsg(int render_widget_id,
+ const base::TimeDelta& max_delay,
+ IPC::Message* msg);
+
+
+ // IO THREAD ONLY -----------------------------------------------------------
+
+ // Called on the IO thread when a PaintRect message is received.
+ void DidReceivePaintMsg(const IPC::Message& msg);
+
+ MessageLoop* ui_loop() { return ui_loop_; }
+
+ void CreateNewWindow(int opener_id, bool user_gesture, int* route_id,
+ HANDLE* modal_dialog_event, HANDLE render_process);
+ void CreateNewWidget(int opener_id, bool activatable, int* route_id);
+
+ private:
+ // A class used to proxy a paint message. PaintMsgProxy objects are created
+ // on the IO thread and destroyed on the UI thread.
+ class PaintMsgProxy;
+ friend class PaintMsgProxy;
+
+ // Map from render_widget_id to live PaintMsgProxy instance.
+ typedef base::hash_map<int, PaintMsgProxy*> PaintMsgProxyMap;
+
+ // Called on the UI thread to discard a paint message.
+ void OnDiscardPaintMsg(PaintMsgProxy* proxy);
+
+ // Called on the UI thread to dispatch a paint message if necessary.
+ void OnDispatchPaintMsg(PaintMsgProxy* proxy);
+
+ // Called on the UI thread to send a message to the RenderProcessHost.
+ void OnSimulateReceivedMessage(const IPC::Message& message);
+
+ // Called on the IO thread to cancel resource requests for the render widget.
+ void OnCancelResourceRequests(ResourceDispatcherHost* dispatcher,
+ int render_widget_id);
+
+ // Called on the IO thread to resume a cross-site response.
+ void OnCrossSiteClosePageACK(ResourceDispatcherHost* dispatcher,
+ int new_render_process_host_id,
+ int new_request_id);
+
+ // A map of live paint messages. Must hold pending_paints_lock_ to access.
+ // The PaintMsgProxy objects are not owned by this map. (See PaintMsgProxy
+ // for details about how the lifetime of instances are managed.)
+ PaintMsgProxyMap pending_paints_;
+ Lock pending_paints_lock_;
+
+ int render_process_id_;
+ MessageLoop* ui_loop_;
+
+ // Event used to implement WaitForPaintMsg.
+ HANDLE event_;
+
+ // The next routing id to use.
+ base::AtomicSequenceNumber next_routing_id_;
+
+ // Whether popup blocking is enabled or not.
+ bool block_popups_;
+
+ DISALLOW_COPY_AND_ASSIGN(RenderWidgetHelper);
+};
+
+#endif // CHROME_BROWSER_RENDEDER_HOST_RENDER_WIDGET_HELPER_H_
diff --git a/chrome/browser/renderer_host/render_widget_host.cc b/chrome/browser/renderer_host/render_widget_host.cc
new file mode 100644
index 0000000..7a77a02
--- /dev/null
+++ b/chrome/browser/renderer_host/render_widget_host.cc
@@ -0,0 +1,849 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/renderer_host/render_widget_host.h"
+
+#include "base/gfx/gdi_util.h"
+#include "base/message_loop.h"
+#include "chrome/app/chrome_dll_resource.h"
+#include "chrome/browser/renderer_host/render_process_host.h"
+#include "chrome/browser/renderer_host/render_widget_helper.h"
+#include "chrome/browser/renderer_host/render_widget_host_view.h"
+#include "chrome/common/mru_cache.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/win_util.h"
+#include "chrome/views/view.h"
+#include "webkit/glue/webcursor.h"
+#include "webkit/glue/webinputevent.h"
+
+using base::Time;
+using base::TimeDelta;
+using base::TimeTicks;
+
+// How long to (synchronously) wait for the renderer to respond with a
+// PaintRect message, when our backing-store is invalid, before giving up and
+// returning a null or incorrectly sized backing-store from GetBackingStore.
+// This timeout impacts the "choppiness" of our window resize perf.
+static const int kPaintMsgTimeoutMS = 40;
+
+// How long to wait before we consider a renderer hung.
+static const int kHungRendererDelayMs = 20000;
+
+///////////////////////////////////////////////////////////////////////////////
+// RenderWidget::BackingStore
+
+RenderWidgetHost::BackingStore::BackingStore(const gfx::Size& size)
+ : size_(size),
+ backing_store_dib_(NULL),
+ original_bitmap_(NULL) {
+ HDC screen_dc = ::GetDC(NULL);
+ hdc_ = CreateCompatibleDC(screen_dc);
+ ReleaseDC(NULL, screen_dc);
+}
+
+RenderWidgetHost::BackingStore::~BackingStore() {
+ DCHECK(hdc_);
+
+ DeleteDC(hdc_);
+
+ if (backing_store_dib_) {
+ DeleteObject(backing_store_dib_);
+ backing_store_dib_ = NULL;
+ }
+}
+
+bool RenderWidgetHost::BackingStore::Refresh(HANDLE process,
+ HANDLE bitmap_section,
+ const gfx::Rect& bitmap_rect) {
+ // The bitmap received is valid only in the renderer process.
+ HANDLE valid_bitmap =
+ win_util::GetSectionFromProcess(bitmap_section, process, false);
+ if (!valid_bitmap)
+ return false;
+
+ if (!backing_store_dib_) {
+ backing_store_dib_ = CreateDIB(hdc_, size_.width(), size_.height(), true,
+ NULL);
+ DCHECK(backing_store_dib_ != NULL);
+ original_bitmap_ = SelectObject(hdc_, backing_store_dib_);
+ }
+
+ // TODO(darin): protect against integer overflow
+ DWORD size = 4 * bitmap_rect.width() * bitmap_rect.height();
+ void* backing_store_data = MapViewOfFile(valid_bitmap, FILE_MAP_READ, 0, 0,
+ size);
+ // These values are shared with gfx::PlatformDevice
+ BITMAPINFOHEADER hdr;
+ gfx::CreateBitmapHeader(bitmap_rect.width(), bitmap_rect.height(), &hdr);
+ // Account for a bitmap_rect that exceeds the bounds of our view
+ gfx::Rect view_rect(0, 0, size_.width(), size_.height());
+ gfx::Rect paint_rect = view_rect.Intersect(bitmap_rect);
+
+ StretchDIBits(hdc_,
+ paint_rect.x(),
+ paint_rect.y(),
+ paint_rect.width(),
+ paint_rect.height(),
+ 0, 0, // source x,y
+ paint_rect.width(),
+ paint_rect.height(),
+ backing_store_data,
+ reinterpret_cast<BITMAPINFO*>(&hdr),
+ DIB_RGB_COLORS,
+ SRCCOPY);
+
+ UnmapViewOfFile(backing_store_data);
+ CloseHandle(valid_bitmap);
+ return true;
+}
+
+HANDLE RenderWidgetHost::BackingStore::CreateDIB(HDC dc, int width, int height,
+ bool use_system_color_depth,
+ HANDLE section) {
+ BITMAPINFOHEADER hdr;
+
+ if (use_system_color_depth) {
+ HDC screen_dc = ::GetDC(NULL);
+ int color_depth = GetDeviceCaps(screen_dc, BITSPIXEL);
+ ::ReleaseDC(NULL, screen_dc);
+
+ // Color depths less than 16 bpp require a palette to be specified in the
+ // BITMAPINFO structure passed to CreateDIBSection. Instead of creating
+ // the palette, we specify the desired color depth as 16 which allows the
+ // OS to come up with an approximation. Tested this with 8bpp.
+ if (color_depth < 16)
+ color_depth = 16;
+
+ gfx::CreateBitmapHeaderWithColorDepth(width, height, color_depth, &hdr);
+ } else {
+ gfx::CreateBitmapHeader(width, height, &hdr);
+ }
+ void* data = NULL;
+ HANDLE dib =
+ CreateDIBSection(hdc_, reinterpret_cast<BITMAPINFO*>(&hdr),
+ 0, &data, section, 0);
+ return dib;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// RenderWidgetHost::BackingStoreManager
+
+// This class manages backing stores in the browsr. Every RenderWidgetHost
+// is associated with a backing store which it requests from this class.
+// The hosts don't maintain any references to the backing stores.
+// These backing stores are maintained in a cache which can be trimmed as
+// needed.
+class RenderWidgetHost::BackingStoreManager {
+ public:
+ // Returns a backing store which matches the desired dimensions.
+ // Parameters:
+ // host
+ // A pointer to the RenderWidgetHost.
+ // backing_store_rect
+ // The desired backing store dimensions.
+ // Returns a pointer to the backing store on success, NULL on failure.
+ static BackingStore* GetBackingStore(RenderWidgetHost* host,
+ const gfx::Size& desired_size) {
+ BackingStore* backing_store = Lookup(host);
+ if (backing_store) {
+ // If we already have a backing store, then make sure it is the correct
+ // size.
+ if (backing_store->size() == desired_size)
+ return backing_store;
+ backing_store = NULL;
+ }
+
+ return backing_store;
+ }
+
+ // Returns a backing store which is fully ready for consumption,
+ // i.e. the bitmap from the renderer has been copied into the
+ // backing store dc, or the bitmap in the backing store dc references
+ // the renderer bitmap.
+ // Parameters:
+ // host
+ // A pointer to the RenderWidgetHost.
+ // backing_store_rect
+ // The desired backing store dimensions.
+ // process_handle
+ // The renderer process handle.
+ // bitmap_section
+ // The bitmap section from the renderer.
+ // bitmap_rect
+ // The rect to be painted into the backing store
+ // needs_full_paint
+ // Set if we need to send out a request to paint the view
+ // to the renderer.
+ static BackingStore* PrepareBackingStore(RenderWidgetHost* host,
+ const gfx::Rect& backing_store_rect,
+ HANDLE process_handle,
+ HANDLE bitmap_section,
+ const gfx::Rect& bitmap_rect,
+ bool* needs_full_paint) {
+ BackingStore* backing_store = GetBackingStore(host,
+ backing_store_rect.size());
+ if (!backing_store) {
+ // We need to get Webkit to generate a new paint here, as we
+ // don't have a previous snapshot.
+ if (bitmap_rect != backing_store_rect) {
+ DCHECK(needs_full_paint != NULL);
+ *needs_full_paint = true;
+ }
+ backing_store = CreateBackingStore(host, backing_store_rect);
+ }
+
+ DCHECK(backing_store != NULL);
+ backing_store->Refresh(process_handle, bitmap_section, bitmap_rect);
+ return backing_store;
+ }
+
+ // Returns a matching backing store for the host.
+ // Returns NULL if we fail to find one.
+ static BackingStore* Lookup(RenderWidgetHost* host) {
+ if (cache_) {
+ BackingStoreCache::iterator it = cache_->Peek(host);
+ if (it != cache_->end())
+ return it->second;
+ }
+ return NULL;
+ }
+
+ // Removes the backing store for the host.
+ static void RemoveBackingStore(RenderWidgetHost* host) {
+ if (!cache_)
+ return;
+
+ BackingStoreCache::iterator it = cache_->Peek(host);
+ if (it == cache_->end())
+ return;
+
+ cache_->Erase(it);
+
+ if (cache_->empty()) {
+ delete cache_;
+ cache_ = NULL;
+ }
+ }
+
+ private:
+ // Not intended for instantiation.
+ ~BackingStoreManager();
+
+ typedef OwningMRUCache<RenderWidgetHost*, BackingStore*> BackingStoreCache;
+ static BackingStoreCache* cache_;
+
+ // Returns the size of the backing store cache.
+ // TODO(iyengar) Make this dynamic, i.e. based on the available resources
+ // on the machine.
+ static int GetBackingStoreCacheSize() {
+ const int kMaxSize = 5;
+ return kMaxSize;
+ }
+
+ // Creates the backing store for the host based on the dimensions passed in.
+ // Removes the existing backing store if there is one.
+ static BackingStore* CreateBackingStore(
+ RenderWidgetHost* host, const gfx::Rect& backing_store_rect) {
+ RemoveBackingStore(host);
+
+ BackingStore* backing_store = new BackingStore(backing_store_rect.size());
+ int backing_store_cache_size = GetBackingStoreCacheSize();
+ if (backing_store_cache_size > 0) {
+ if (!cache_)
+ cache_ = new BackingStoreCache(backing_store_cache_size);
+ cache_->Put(host, backing_store);
+ }
+ return backing_store;
+ }
+
+ DISALLOW_EVIL_CONSTRUCTORS(BackingStoreManager);
+};
+
+RenderWidgetHost::BackingStoreManager::BackingStoreCache*
+ RenderWidgetHost::BackingStoreManager::cache_ = NULL;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// RenderWidgetHost
+
+RenderWidgetHost::RenderWidgetHost(RenderProcessHost* process,
+ int routing_id)
+ : process_(process),
+ routing_id_(routing_id),
+ resize_ack_pending_(false),
+ mouse_move_pending_(false),
+ view_(NULL),
+ is_loading_(false),
+ is_hidden_(false),
+ suppress_view_updating_(false),
+ needs_repainting_on_restore_(false),
+ is_unresponsive_(false),
+ view_being_painted_(false),
+ repaint_ack_pending_(false) {
+ if (routing_id_ == MSG_ROUTING_NONE)
+ routing_id_ = process_->GetNextRoutingID();
+
+ process_->Attach(this, routing_id_);
+ // Because the widget initializes as is_hidden_ == false,
+ // tell the process host that we're alive.
+ process_->WidgetRestored();
+}
+
+RenderWidgetHost::~RenderWidgetHost() {
+ // Clear our current or cached backing store if either remains.
+ BackingStoreManager::RemoveBackingStore(this);
+
+ process_->Release(routing_id_);
+}
+
+void RenderWidgetHost::Init() {
+ DCHECK(process_->channel());
+
+ // Send the ack along with the information on placement.
+ HWND plugin_hwnd = view_->GetPluginHWND();
+ Send(new ViewMsg_CreatingNew_ACK(routing_id_, plugin_hwnd));
+
+ WasResized();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// RenderWidgetHost, protected:
+
+IPC_DEFINE_MESSAGE_MAP(RenderWidgetHost)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_RendererReady, OnMsgRendererReady)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_RendererGone, OnMsgRendererGone)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_Close, OnMsgClose)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_RequestMove, OnMsgRequestMove)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_PaintRect, OnMsgPaintRect)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_ScrollRect, OnMsgScrollRect)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_HandleInputEvent_ACK, OnMsgInputEventAck)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_Focus, OnMsgFocus)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_Blur, OnMsgBlur)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_SetCursor, OnMsgSetCursor)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_ImeUpdateStatus, OnMsgImeUpdateStatus)
+ IPC_MESSAGE_UNHANDLED_ERROR()
+IPC_END_MESSAGE_MAP()
+
+void RenderWidgetHost::OnMsgRendererReady() {
+ WasResized();
+}
+
+void RenderWidgetHost::OnMsgRendererGone() {
+ // TODO(evanm): This synchronously ends up calling "delete this".
+ // Is that really what we want in response to this message? I'm matching
+ // previous behavior of the code here.
+ Destroy();
+}
+
+void RenderWidgetHost::OnMsgClose() {
+ Shutdown();
+}
+
+void RenderWidgetHost::OnMsgRequestMove(const gfx::Rect& pos) {
+ // Note that we ignore the position.
+ view_->SetSize(pos.size());
+}
+
+void RenderWidgetHost::OnMsgPaintRect(
+ const ViewHostMsg_PaintRect_Params& params) {
+ TimeTicks paint_start = TimeTicks::Now();
+
+ // Update our knowledge of the RenderWidget's size.
+ current_size_ = params.view_size;
+
+ bool is_resize_ack =
+ ViewHostMsg_PaintRect_Flags::is_resize_ack(params.flags);
+
+ // resize_ack_pending_ needs to be cleared before we call DidPaintRect, since
+ // that will end up reaching GetBackingStore.
+ if (is_resize_ack) {
+ DCHECK(resize_ack_pending_);
+ resize_ack_pending_ = false;
+ }
+
+ bool is_repaint_ack =
+ ViewHostMsg_PaintRect_Flags::is_repaint_ack(params.flags);
+ if (is_repaint_ack) {
+ repaint_ack_pending_ = false;
+ TimeDelta delta = TimeTicks::Now() - repaint_start_time_;
+ UMA_HISTOGRAM_TIMES(L"MPArch.RWH_RepaintDelta", delta);
+ }
+
+ DCHECK(params.bitmap);
+ DCHECK(!params.bitmap_rect.IsEmpty());
+ DCHECK(!params.view_size.IsEmpty());
+
+ PaintRect(params.bitmap, params.bitmap_rect, params.view_size);
+
+ // ACK early so we can prefetch the next PaintRect if there is a next one.
+ Send(new ViewMsg_PaintRect_ACK(routing_id_));
+
+ // TODO(darin): This should really be done by the view_!
+ MovePluginWindows(params.plugin_window_moves);
+
+ // The view might be destroyed already. Check for this case.
+ if (view_ && !suppress_view_updating_) {
+ view_being_painted_ = true;
+ view_->DidPaintRect(params.bitmap_rect);
+ view_being_painted_ = false;
+ }
+
+ if (paint_observer_.get())
+ paint_observer_->RenderWidgetHostDidPaint(this);
+
+ // If we got a resize ack, then perhaps we have another resize to send?
+ if (is_resize_ack && view_) {
+ gfx::Rect view_bounds = view_->GetViewBounds();
+ if (current_size_.width() != view_bounds.width() ||
+ current_size_.height() != view_bounds.height()) {
+ WasResized();
+ }
+ }
+
+ // Log the time delta for processing a paint message.
+ TimeDelta delta = TimeTicks::Now() - paint_start;
+ UMA_HISTOGRAM_TIMES(L"MPArch.RWH_OnMsgPaintRect", delta);
+}
+
+void RenderWidgetHost::OnMsgScrollRect(
+ const ViewHostMsg_ScrollRect_Params& params) {
+ TimeTicks scroll_start = TimeTicks::Now();
+
+ DCHECK(!params.view_size.IsEmpty());
+
+ ScrollRect(params.bitmap, params.bitmap_rect, params.dx, params.dy,
+ params.clip_rect, params.view_size);
+
+ // ACK early so we can prefetch the next ScrollRect if there is a next one.
+ Send(new ViewMsg_ScrollRect_ACK(routing_id_));
+
+ // TODO(darin): This should really be done by the view_!
+ MovePluginWindows(params.plugin_window_moves);
+
+ // The view might be destroyed already. Check for this case
+ if (view_) {
+ view_being_painted_ = true;
+ view_->DidScrollRect(params.clip_rect, params.dx, params.dy);
+ view_being_painted_ = false;
+ }
+
+ // Log the time delta for processing a scroll message.
+ TimeDelta delta = TimeTicks::Now() - scroll_start;
+ UMA_HISTOGRAM_TIMES(L"MPArch.RWH_OnMsgScrollRect", delta);
+}
+
+void RenderWidgetHost::MovePluginWindows(
+ const std::vector<WebPluginGeometry>& plugin_window_moves) {
+ if (plugin_window_moves.empty())
+ return;
+
+ HDWP defer_window_pos_info =
+ ::BeginDeferWindowPos(static_cast<int>(plugin_window_moves.size()));
+
+ if (!defer_window_pos_info) {
+ NOTREACHED();
+ return;
+ }
+
+ for (size_t i = 0; i < plugin_window_moves.size(); ++i) {
+ unsigned long flags = 0;
+ const WebPluginGeometry& move = plugin_window_moves[i];
+
+ if (move.visible)
+ flags |= SWP_SHOWWINDOW;
+ else
+ flags |= SWP_HIDEWINDOW;
+
+ HRGN hrgn = ::CreateRectRgn(move.clip_rect.x(),
+ move.clip_rect.y(),
+ move.clip_rect.right(),
+ move.clip_rect.bottom());
+ gfx::SubtractRectanglesFromRegion(hrgn, move.cutout_rects);
+
+ // Note: System will own the hrgn after we call SetWindowRgn,
+ // so we don't need to call DeleteObject(hrgn)
+ ::SetWindowRgn(move.window, hrgn, !move.clip_rect.IsEmpty());
+
+ defer_window_pos_info = ::DeferWindowPos(defer_window_pos_info,
+ move.window, NULL,
+ move.window_rect.x(),
+ move.window_rect.y(),
+ move.window_rect.width(),
+ move.window_rect.height(), flags);
+ if (!defer_window_pos_info) {
+ return;
+ }
+ }
+
+ ::EndDeferWindowPos(defer_window_pos_info);
+}
+
+void RenderWidgetHost::OnMsgInputEventAck(const IPC::Message& message) {
+ // Log the time delta for processing an input event.
+ TimeDelta delta = TimeTicks::Now() - input_event_start_time_;
+ UMA_HISTOGRAM_TIMES(L"MPArch.RWH_InputEventDelta", delta);
+
+ // Cancel pending hung renderer checks since the renderer is responsive.
+ StopHangMonitorTimeout();
+
+ void* iter = NULL;
+ int type = 0;
+ bool r = message.ReadInt(&iter, &type);
+ DCHECK(r);
+
+ if (type == WebInputEvent::MOUSE_MOVE) {
+ mouse_move_pending_ = false;
+
+ // now, we can send the next mouse move event
+ if (next_mouse_move_.get()) {
+ DCHECK(next_mouse_move_->type == WebInputEvent::MOUSE_MOVE);
+ ForwardMouseEvent(*next_mouse_move_);
+ }
+ }
+
+ const char* data = NULL;
+ int length = 0;
+ if (message.ReadData(&iter, &data, &length)) {
+ const WebInputEvent* input_event =
+ reinterpret_cast<const WebInputEvent*>(data);
+ UnhandledInputEvent(*input_event);
+ }
+}
+
+void RenderWidgetHost::OnMsgFocus() {
+ // Only the user can focus a RenderWidgetHost.
+ NOTREACHED();
+}
+
+void RenderWidgetHost::OnMsgBlur() {
+ if (view_) {
+ view_->Blur();
+ }
+}
+
+void RenderWidgetHost::OnMsgSetCursor(const WebCursor& cursor) {
+ if (!view_) {
+ return;
+ }
+ view_->UpdateCursor(cursor);
+}
+
+void RenderWidgetHost::OnMsgImeUpdateStatus(ViewHostMsg_ImeControl control,
+ const gfx::Rect& caret_rect) {
+ if (view_) {
+ view_->IMEUpdateStatus(control, caret_rect);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void RenderWidgetHost::WasHidden() {
+ is_hidden_ = true;
+
+ // Don't bother reporting hung state when we aren't the active tab.
+ StopHangMonitorTimeout();
+
+ // If we have a renderer, then inform it that we are being hidden so it can
+ // reduce its resource utilization.
+ Send(new ViewMsg_WasHidden(routing_id_));
+
+ // TODO(darin): what about constrained windows? it doesn't look like they
+ // see a message when their parent is hidden. maybe there is something more
+ // generic we can do at the TabContents API level instead of relying on
+ // Windows messages.
+
+ // Tell the RenderProcessHost we were hidden.
+ process_->WidgetHidden();
+}
+
+void RenderWidgetHost::WasRestored() {
+ // When we create the widget, it is created as *not* hidden.
+ if (!is_hidden_)
+ return;
+ is_hidden_ = false;
+
+ BackingStore* backing_store = BackingStoreManager::Lookup(this);
+ // If we already have a backing store for this widget, then we don't need to
+ // repaint on restore _unless_ we know that our backing store is invalid.
+ bool needs_repainting;
+ if (needs_repainting_on_restore_ || !backing_store) {
+ needs_repainting = true;
+ needs_repainting_on_restore_ = false;
+ } else {
+ needs_repainting = false;
+ }
+ Send(new ViewMsg_WasRestored(routing_id_, needs_repainting));
+
+ process_->WidgetRestored();
+}
+
+void RenderWidgetHost::WasResized() {
+ if (resize_ack_pending_ || !process_->channel() || !view_)
+ return;
+
+ gfx::Rect view_bounds = view_->GetViewBounds();
+ gfx::Size new_size(view_bounds.width(), view_bounds.height());
+
+ // Avoid asking the RenderWidget to resize to its current size, since it
+ // won't send us a PaintRect message in that case.
+ if (new_size == current_size_)
+ return;
+
+ // We don't expect to receive an ACK when the requested size is empty.
+ if (!new_size.IsEmpty())
+ resize_ack_pending_ = true;
+
+ if (!Send(new ViewMsg_Resize(routing_id_, new_size)))
+ resize_ack_pending_ = false;
+}
+
+void RenderWidgetHost::ForwardMouseEvent(const WebMouseEvent& mouse_event) {
+ // Avoid spamming the renderer with mouse move events. It is important
+ // to note that WM_MOUSEMOVE events are anyways synthetic, but since our
+ // thread is able to rapidly consume WM_MOUSEMOVE events, we may get way
+ // more WM_MOUSEMOVE events than we wish to send to the renderer.
+ if (mouse_event.type == WebInputEvent::MOUSE_MOVE) {
+ if (mouse_move_pending_) {
+ next_mouse_move_.reset(new WebMouseEvent(mouse_event));
+ return;
+ }
+ mouse_move_pending_ = true;
+ }
+
+ ForwardInputEvent(mouse_event, sizeof(WebMouseEvent));
+}
+
+void RenderWidgetHost::ForwardKeyboardEvent(
+ const WebKeyboardEvent& key_event) {
+ ForwardInputEvent(key_event, sizeof(WebKeyboardEvent));
+}
+
+void RenderWidgetHost::ForwardWheelEvent(
+ const WebMouseWheelEvent& wheel_event) {
+ ForwardInputEvent(wheel_event, sizeof(WebMouseWheelEvent));
+}
+
+void RenderWidgetHost::ForwardInputEvent(const WebInputEvent& input_event,
+ int event_size) {
+ if (!process_->channel())
+ return;
+
+ IPC::Message* message = new ViewMsg_HandleInputEvent(routing_id_);
+ message->WriteData(
+ reinterpret_cast<const char*>(&input_event), event_size);
+ input_event_start_time_ = TimeTicks::Now();
+ Send(message);
+
+ // any input event cancels a pending mouse move event
+ next_mouse_move_.reset();
+
+ StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kHungRendererDelayMs));
+}
+
+void RenderWidgetHost::Shutdown() {
+ if (process_->channel()) {
+ // Tell the renderer object to close.
+ process_->ReportExpectingClose(routing_id_);
+ bool rv = Send(new ViewMsg_Close(routing_id_));
+ DCHECK(rv);
+ }
+
+ Destroy();
+}
+
+void RenderWidgetHost::Focus() {
+ Send(new ViewMsg_SetFocus(routing_id_, true));
+}
+
+void RenderWidgetHost::Blur() {
+ Send(new ViewMsg_SetFocus(routing_id_, false));
+}
+
+void RenderWidgetHost::LostCapture() {
+ Send(new ViewMsg_MouseCaptureLost(routing_id_));
+}
+
+void RenderWidgetHost::ViewDestroyed() {
+ // TODO(evanm): tracking this may no longer be necessary;
+ // eliminate this function if so.
+ view_ = NULL;
+}
+
+void RenderWidgetHost::Destroy() {
+ NotificationService::current()->Notify(
+ NOTIFY_RENDER_WIDGET_HOST_DESTROYED,
+ Source<RenderWidgetHost>(this),
+ NotificationService::NoDetails());
+
+ // Tell the view to die.
+ // Note that in the process of the view shutting down, it can call a ton
+ // of other messages on us. So if you do any other deinitialization here,
+ // do it after this call to view_->Destroy().
+ if (view_)
+ view_->Destroy();
+
+ delete this;
+}
+
+void RenderWidgetHost::CheckRendererIsUnresponsive() {
+ // If we received a call to StopHangMonitorTimeout.
+ if (time_when_considered_hung_.is_null())
+ return;
+
+ // If we have not waited long enough, then wait some more.
+ Time now = Time::Now();
+ if (now < time_when_considered_hung_) {
+ StartHangMonitorTimeout(time_when_considered_hung_ - now);
+ return;
+ }
+
+ // OK, looks like we have a hung renderer!
+ NotificationService::current()->Notify(NOTIFY_RENDERER_PROCESS_HANG,
+ Source<RenderWidgetHost>(this),
+ NotificationService::NoDetails());
+ is_unresponsive_ = true;
+ NotifyRendererUnresponsive();
+}
+
+void RenderWidgetHost::RendererIsResponsive() {
+ if (is_unresponsive_) {
+ is_unresponsive_ = false;
+ NotifyRendererResponsive();
+ }
+}
+
+bool RenderWidgetHost::Send(IPC::Message* msg) {
+ return process_->Send(msg);
+}
+
+void RenderWidgetHost::SetIsLoading(bool is_loading) {
+ is_loading_ = is_loading;
+ if (!view_)
+ return;
+ view_->SetIsLoading(is_loading);
+}
+
+RenderWidgetHost::BackingStore* RenderWidgetHost::GetBackingStore() {
+ // We should not be asked to paint while we are hidden. If we are hidden,
+ // then it means that our consumer failed to call WasRestored.
+ DCHECK(!is_hidden_) << "GetBackingStore called while hidden!";
+
+ // We might have a cached backing store that we can reuse!
+ BackingStore* backing_store =
+ BackingStoreManager::GetBackingStore(this, current_size_);
+ // If we fail to find a backing store in the cache, send out a request
+ // to the renderer to paint the view if required.
+ if (!backing_store && !repaint_ack_pending_ && !resize_ack_pending_ &&
+ !view_being_painted_) {
+ repaint_start_time_ = TimeTicks::Now();
+ repaint_ack_pending_ = true;
+ Send(new ViewMsg_Repaint(routing_id_, current_size_));
+ }
+
+ // When we have asked the RenderWidget to resize, and we are still waiting on
+ // a response, block for a little while to see if we can't get a response
+ // before returning the old (incorrectly sized) backing store.
+ if (resize_ack_pending_ || !backing_store) {
+ IPC::Message msg;
+ TimeDelta max_delay = TimeDelta::FromMilliseconds(kPaintMsgTimeoutMS);
+ if (process_->WaitForPaintMsg(routing_id_, max_delay, &msg)) {
+ suppress_view_updating_ = true;
+ ViewHostMsg_PaintRect::Dispatch(
+ &msg, this, &RenderWidgetHost::OnMsgPaintRect);
+ suppress_view_updating_ = false;
+ backing_store = BackingStoreManager::GetBackingStore(this, current_size_);
+ }
+ }
+
+ return backing_store;
+}
+
+void RenderWidgetHost::PaintRect(HANDLE bitmap, const gfx::Rect& bitmap_rect,
+ const gfx::Size& view_size) {
+ if (is_hidden_) {
+ needs_repainting_on_restore_ = true;
+ return;
+ }
+
+ // We use the view size according to the render view, which may not be
+ // quite the same as the size of our window.
+ gfx::Rect view_rect(0, 0, view_size.width(), view_size.height());
+
+ bool needs_full_paint = false;
+ BackingStore* backing_store =
+ BackingStoreManager::PrepareBackingStore(this, view_rect,
+ process_->process().handle(),
+ bitmap, bitmap_rect,
+ &needs_full_paint);
+ DCHECK(backing_store != NULL);
+ if (needs_full_paint) {
+ repaint_start_time_ = TimeTicks::Now();
+ repaint_ack_pending_ = true;
+ Send(new ViewMsg_Repaint(routing_id_, view_size));
+ }
+}
+
+void RenderWidgetHost::ScrollRect(HANDLE bitmap, const gfx::Rect& bitmap_rect,
+ int dx, int dy, const gfx::Rect& clip_rect,
+ const gfx::Size& view_size) {
+ if (is_hidden_) {
+ needs_repainting_on_restore_ = true;
+ return;
+ }
+
+ // TODO(darin): do we need to do something else if our backing store is not
+ // the same size as the advertised view? maybe we just assume there is a
+ // full paint on its way?
+ BackingStore* backing_store = BackingStoreManager::Lookup(this);
+ if (!backing_store || (backing_store->size() != view_size))
+ return;
+
+ RECT damaged_rect, r = clip_rect.ToRECT();
+ ScrollDC(backing_store->dc(), dx, dy, NULL, &r, NULL, &damaged_rect);
+
+ // TODO(darin): this doesn't work if dx and dy are both non-zero!
+ DCHECK(dx == 0 || dy == 0);
+
+ // We expect that damaged_rect should equal bitmap_rect.
+ DCHECK(gfx::Rect(damaged_rect) == bitmap_rect);
+
+ backing_store->Refresh(process_->process().handle(), bitmap, bitmap_rect);
+}
+
+void RenderWidgetHost::RestartHangMonitorTimeout() {
+ StartHangMonitorTimeout(TimeDelta::FromMilliseconds(kHungRendererDelayMs));
+}
+
+void RenderWidgetHost::StopHangMonitorTimeout() {
+ time_when_considered_hung_ = Time();
+ RendererIsResponsive();
+
+ // We do not bother to stop the hung_renderer_timer_ here in case it will be
+ // started again shortly, which happens to be the common use case.
+}
+
+void RenderWidgetHost::StartHangMonitorTimeout(TimeDelta delay) {
+ time_when_considered_hung_ = Time::Now() + delay;
+
+ // If we already have a timer that will expire at or before the given delay,
+ // then we have nothing more to do now.
+ if (hung_renderer_timer_.IsRunning() &&
+ hung_renderer_timer_.GetCurrentDelay() <= delay)
+ return;
+
+ // Either the timer is not yet running, or we need to adjust the timer to
+ // fire sooner.
+ hung_renderer_timer_.Stop();
+ hung_renderer_timer_.Start(delay, this,
+ &RenderWidgetHost::CheckRendererIsUnresponsive);
+}
+
+void RenderWidgetHost::RendererExited() {
+ BackingStoreManager::RemoveBackingStore(this);
+}
+
+void RenderWidgetHost::SystemThemeChanged() {
+ Send(new ViewMsg_ThemeChanged(routing_id_));
+}
diff --git a/chrome/browser/renderer_host/render_widget_host.h b/chrome/browser/renderer_host/render_widget_host.h
new file mode 100644
index 0000000..d683e84
--- /dev/null
+++ b/chrome/browser/renderer_host/render_widget_host.h
@@ -0,0 +1,369 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_H_
+#define CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_H_
+
+#include <windows.h>
+
+#include <vector>
+
+#include "base/gfx/size.h"
+#include "base/timer.h"
+#include "chrome/common/ipc_channel.h"
+
+namespace gfx {
+class Rect;
+}
+
+class BackingStore;
+class PaintObserver;
+class RenderProcessHost;
+class RenderWidgetHostView;
+class WebInputEvent;
+class WebKeyboardEvent;
+class WebMouseEvent;
+class WebMouseWheelEvent;
+class WebCursor;
+enum ViewHostMsg_ImeControl;
+struct ViewHostMsg_PaintRect_Params;
+struct ViewHostMsg_ScrollRect_Params;
+struct WebPluginGeometry;
+
+// This class manages the browser side of a browser<->renderer HWND connection.
+// The HWND lives in the browser process, and windows events are sent over
+// IPC to the corresponding object in the renderer. The renderer paints into
+// shared memory, which we transfer to a backing store and blit to the screen
+// when Windows sends us a WM_PAINT message.
+//
+// How Shutdown Works
+//
+// There are two situations in which this object, a RenderWidgetHost, can be
+// instantiated:
+//
+// 1. By a WebContents as the communication conduit for a rendered web page.
+// The WebContents instantiates a derived class: RenderViewHost.
+// 2. By a WebContents as the communication conduit for a select widget. The
+// WebContents instantiates the RenderWidgetHost directly.
+//
+// For every WebContents there are several objects in play that need to be
+// properly destroyed or cleaned up when certain events occur.
+//
+// - WebContents - the TabContents itself, and its associated HWND.
+// - RenderViewHost - representing the communication conduit with the child
+// process.
+// - RenderWidgetHostView - the view of the web page content, message handler,
+// and plugin root.
+//
+// Normally, the WebContents contains a child RenderWidgetHostView that renders
+// the contents of the loaded page. It has a WS_CLIPCHILDREN style so that it
+// does no painting of its own.
+//
+// The lifetime of the RenderWidgetHostView is tied to the render process. If
+// the render process dies, the RenderWidgetHostView goes away and all
+// references to it must become NULL. If the WebContents finds itself without a
+// RenderWidgetHostView, it paints Sad Tab instead.
+//
+// RenderViewHost (a RenderWidgetHost subclass) is the conduit used to
+// communicate with the RenderView and is owned by the WebContents. If the
+// render process crashes, the RenderViewHost remains and restarts the render
+// process if needed to continue navigation.
+//
+// The WebContents is itself owned by the NavigationController in which it
+// resides.
+//
+// Some examples of how shutdown works:
+//
+// When a tab is closed (either by the user, the web page calling window.close,
+// etc) the TabStrip destroys the associated NavigationController, which calls
+// Destroy on each TabContents it owns.
+//
+// For a WebContents, its Destroy method tells the RenderViewHost to
+// shut down the render process and die.
+//
+// When the render process is destroyed it destroys the View: the
+// RenderWidgetHostView, which destroys its HWND and deletes that object.
+//
+// For select popups, the situation is a little different. The RenderWidgetHost
+// associated with the select popup owns the view and itself (is responsible
+// for destroying itself when the view is closed). The WebContents's only
+// responsibility is to select popups is to create them when it is told to. When
+// the View is destroyed via an IPC message (for when WebCore destroys the
+// popup, e.g. if the user selects one of the options), or because
+// WM_CANCELMODE is received by the view, the View schedules the destruction of
+// the render process. However in this case since there's no WebContents
+// container, when the render process is destroyed, the RenderWidgetHost just
+// deletes itself, which is safe because no one else should have any references
+// to it (the WebContents does not).
+//
+// It should be noted that the RenderViewHost, not the RenderWidgetHost,
+// handles IPC messages relating to the render process going away, since the
+// way a RenderViewHost (WebContents) handles the process dying is different to
+// the way a select popup does. As such the RenderWidgetHostView handles these
+// messages for select popups. This placement is more out of convenience than
+// anything else. When the view is live, these messages are forwarded to it by
+// the RenderWidgetHost's IPC message map.
+//
+class RenderWidgetHost : public IPC::Channel::Listener {
+ public:
+ // routing_id can be MSG_ROUTING_NONE, in which case the next available
+ // routing id is taken from the RenderProcessHost.
+ RenderWidgetHost(RenderProcessHost* process, int routing_id);
+ virtual ~RenderWidgetHost();
+
+ // Gets/Sets the View of this RenderWidgetHost. Can be NULL, e.g. if the
+ // RenderWidget is being destroyed or the render process crashed. You should
+ // never cache this pointer since it can become NULL if the renderer crashes,
+ // instead you should always ask for it using the accessor.
+ void set_view(RenderWidgetHostView* view) { view_ = view; }
+ RenderWidgetHostView* view() const { return view_; }
+
+ RenderProcessHost* process() const { return process_; }
+ int routing_id() const { return routing_id_; }
+
+ // Manual RTTI FTW. We are not hosting a web page.
+ virtual bool IsRenderView() { return false; }
+
+ // Called when a renderer object already been created for this host, and we
+ // just need to be attached to it. Used for window.open, <select> dropdown
+ // menus, and other times when the renderer initiates creating an object.
+ virtual void Init();
+
+ // IPC::Channel::Listener
+ virtual void OnMessageReceived(const IPC::Message& msg);
+
+ // Sends a message to the corresponding object in the renderer.
+ bool Send(IPC::Message* msg);
+
+ // Called to notify the RenderWidget that it has been hidden or restored from
+ // having been hidden.
+ void WasHidden();
+ void WasRestored();
+
+ // Called to notify the RenderWidget that it has been resized.
+ void WasResized();
+
+ // Tells the renderer to die and then calls Destroy().
+ virtual void Shutdown();
+
+ void Focus();
+ void Blur();
+ void LostCapture();
+
+ // Notifies the RenderWidgetHost that the View was destroyed.
+ void ViewDestroyed();
+
+ // Indicates if the page has finished loading.
+ virtual void SetIsLoading(bool is_loading);
+
+ // Represents a device-dependent drawing surface used to hold the rendering
+ // of a RenderWidgetHost.
+ class BackingStore;
+
+ // Manages a set of backing stores.
+ class BackingStoreManager;
+
+ // Get access to the widget's backing store. If a resize is in progress,
+ // then the current size of the backing store may be less than the size of
+ // the widget's view. This method returns NULL if the backing store could
+ // not be created.
+ BackingStore* GetBackingStore();
+
+ // An interface that gets called when paints happen.
+ // Used in performance tests.
+ class PaintObserver;
+ // Set the PaintObserver on this object. Takes ownership.
+ void SetPaintObserver(PaintObserver* paint_observer) {
+ paint_observer_.reset(paint_observer);
+ }
+
+ // Checks to see if we can give up focus to this widget through a
+ // javascript call.
+ virtual bool CanBlur() const { return true; }
+
+ // Restart the active hang monitor timeout. Clears all existing timeouts and
+ // starts with a new one. This can be because the renderer has become
+ // active, the tab is being hidden, or the user has chosen to wait some more
+ // to give the tab a chance to become active and we don't want to display a
+ // warning too soon.
+ void RestartHangMonitorTimeout();
+
+ // Stops all existing hang monitor timeouts and assumes the renderer is
+ // responsive.
+ void StopHangMonitorTimeout();
+
+ // Starts a hang monitor timeout. If there's already a hang monitor timeout
+ // the new one will only fire if it has a shorter delay than the time
+ // left on the existing timeouts.
+ void StartHangMonitorTimeout(base::TimeDelta delay);
+
+ // Called when we receive a notification indicating that the renderer
+ // process has gone.
+ void RendererExited();
+
+ // Called when the system theme changes. At this time all existing native
+ // theme handles are invalid and the renderer must obtain new ones and
+ // repaint.
+ void SystemThemeChanged();
+
+ protected:
+ // Called when we an InputEvent was not processed by the renderer.
+ virtual void UnhandledInputEvent(const WebInputEvent& event) { }
+
+ // IPC message handlers
+ void OnMsgRendererReady();
+ void OnMsgRendererGone();
+ void OnMsgClose();
+ void OnMsgRequestMove(const gfx::Rect& pos);
+ void OnMsgResizeAck();
+ void OnMsgPaintRect(const ViewHostMsg_PaintRect_Params& params);
+ void OnMsgScrollRect(const ViewHostMsg_ScrollRect_Params& params);
+ void OnMsgInputEventAck(const IPC::Message& message);
+ void OnMsgFocus();
+ void OnMsgBlur();
+ void OnMsgSetCursor(const WebCursor& cursor);
+ void OnMsgImeUpdateStatus(ViewHostMsg_ImeControl control,
+ const gfx::Rect& caret_rect);
+
+ void MovePluginWindows(
+ const std::vector<WebPluginGeometry>& plugin_window_moves);
+
+ // TODO(beng): (Cleanup) remove this friendship once we expose a clean API to
+ // RenderWidgetHost Views. This exists only to give RenderWidgetHostView
+ // access to Forward*Event.
+ friend class RenderWidgetHostViewWin;
+
+ void ForwardMouseEvent(const WebMouseEvent& mouse_event);
+ virtual void ForwardKeyboardEvent(const WebKeyboardEvent& key_event);
+ void ForwardWheelEvent(const WebMouseWheelEvent& wheel_event);
+ void ForwardInputEvent(const WebInputEvent& input_event, int event_size);
+
+ // Called to paint a region of the backing store
+ void PaintRect(HANDLE bitmap, const gfx::Rect& bitmap_rect,
+ const gfx::Size& view_size);
+
+ // Called to scroll a region of the backing store
+ void ScrollRect(HANDLE bitmap, const gfx::Rect& bitmap_rect, int dx, int dy,
+ const gfx::Rect& clip_rect, const gfx::Size& view_size);
+
+ // Tell this object to destroy itself.
+ void Destroy();
+
+ // Callbacks for notification when the renderer becomes unresponsive to user
+ // input events, and subsequently responsive again. The delegate can use
+ // these notifications to show a warning.
+ void CheckRendererIsUnresponsive();
+ virtual void NotifyRendererUnresponsive() {}
+ void RendererIsResponsive();
+ virtual void NotifyRendererResponsive() {}
+
+ // Created during construction but initialized during Init*(). Therefore, it
+ // is guaranteed never to be NULL, but its channel may be NULL if the
+ // renderer crashed, so you must always check that.
+ RenderProcessHost* process_;
+
+ // The ID of the corresponding object in the Renderer Instance.
+ int routing_id_;
+
+ bool resize_ack_pending_; // True when waiting for RESIZE_ACK.
+ gfx::Size current_size_; // The current size of the RenderWidget.
+
+ // True if a mouse move event was sent to the render view and we are waiting
+ // for a corresponding ViewHostMsg_HandleInputEvent_ACK message.
+ bool mouse_move_pending_;
+
+ // The next mouse move event to send (only non-null while mouse_move_pending_
+ // is true).
+ scoped_ptr<WebMouseEvent> next_mouse_move_;
+
+ // The View associated with the RenderViewHost. The lifetime of this object
+ // is associated with the lifetime of the Render process. If the Renderer
+ // crashes, its View is destroyed and this pointer becomes NULL, even though
+ // render_view_host_ lives on to load another URL (creating a new View while
+ // doing so).
+ RenderWidgetHostView* view_;
+
+ // The time when an input event was sent to the RenderWidget.
+ base::TimeTicks input_event_start_time_;
+
+ // Indicates whether a page is loading or not.
+ bool is_loading_;
+ // Indicates whether a page is hidden or not.
+ bool is_hidden_;
+ // If true, then we should not ask our view to repaint when our backingstore
+ // is updated.
+ bool suppress_view_updating_;
+
+ // If true, then we should repaint when restoring even if we have a
+ // backingstore. This flag is set to true if we receive a paint message
+ // while is_hidden_ to true. Even though we tell the render widget to hide
+ // itself, a paint message could already be in flight at that point.
+ bool needs_repainting_on_restore_;
+
+ // The following value indicates a time in the future when we would consider
+ // the renderer hung if it does not generate an appropriate response message.
+ base::Time time_when_considered_hung_;
+
+ // This timer runs to check if time_when_considered_hung_ has past.
+ base::OneShotTimer<RenderWidgetHost> hung_renderer_timer_;
+
+ // This is true if the renderer is currently unresponsive.
+ bool is_unresponsive_;
+
+ // Optional observer that listens for notifications of painting.
+ scoped_ptr<PaintObserver> paint_observer_;
+
+ // Set when we call DidPaintRect/DidScrollRect on the view.
+ bool view_being_painted_;
+
+ // Set if we are waiting for a repaint ack for the view.
+ bool repaint_ack_pending_;
+
+ // Used for UMA histogram logging to measure the time for a repaint view
+ // operation to finish.
+ base::TimeTicks repaint_start_time_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(RenderWidgetHost);
+};
+
+class RenderWidgetHost::BackingStore {
+ public:
+ BackingStore(const gfx::Size& size);
+ ~BackingStore();
+
+ HDC dc() { return hdc_; }
+ const gfx::Size& size() { return size_; }
+
+ // Paints the bitmap from the renderer onto the backing store.
+ bool Refresh(HANDLE process, HANDLE bitmap_section,
+ const gfx::Rect& bitmap_rect);
+
+ private:
+ // Creates a dib conforming to the height/width/section parameters passed
+ // in. The use_os_color_depth parameter controls whether we use the color
+ // depth to create an appropriate dib or not.
+ HANDLE CreateDIB(HDC dc, int width, int height, bool use_os_color_depth,
+ HANDLE section);
+
+ // The backing store dc.
+ HDC hdc_;
+ // The size of the backing store.
+ gfx::Size size_;
+ // Handle to the backing store dib.
+ HANDLE backing_store_dib_;
+ // Handle to the original bitmap in the dc.
+ HANDLE original_bitmap_;
+
+ DISALLOW_COPY_AND_ASSIGN(BackingStore);
+};
+
+class RenderWidgetHost::PaintObserver {
+ public:
+ virtual ~PaintObserver() {}
+
+ // Called each time the RenderWidgetHost paints.
+ virtual void RenderWidgetHostDidPaint(RenderWidgetHost* rwh) = 0;
+};
+
+#endif // #ifndef CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_H_
diff --git a/chrome/browser/renderer_host/render_widget_host_view.h b/chrome/browser/renderer_host/render_widget_host_view.h
new file mode 100644
index 0000000..8e6152f
--- /dev/null
+++ b/chrome/browser/renderer_host/render_widget_host_view.h
@@ -0,0 +1,121 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_VIEW_H_
+#define CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_VIEW_H_
+
+#include <windows.h>
+
+#include "base/shared_memory.h"
+#include "chrome/common/render_messages.h"
+
+namespace gfx {
+class Rect;
+class Size;
+}
+namespace IPC {
+class Message;
+}
+
+class RenderProcessHost;
+class RenderWidgetHost;
+class WebCursor;
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// RenderWidgetHostView
+//
+// RenderWidgetHostView is an interface implemented by an object that acts as
+// the "View" portion of a RenderWidgetHost. The RenderWidgetHost and its
+// associated RenderProcessHost own the "Model" in this case which is the
+// child renderer process. The View is responsible for receiving events from
+// the surrounding environment and passing them to the RenderWidgetHost, and
+// for actually displaying the content of the RenderWidgetHost when it
+// changes.
+//
+///////////////////////////////////////////////////////////////////////////////
+class RenderWidgetHostView {
+ public:
+ // Platform-specific creator. Use this to construct new RenderWidgetHostViews
+ // rather than using RenderWidgetHostViewWin & friends.
+ //
+ // The RenderWidgetHost must already be created (because we can't know if it's
+ // going to be a regular RenderWidgetHost or a RenderViewHost (a subclass).
+ static RenderWidgetHostView* CreateViewForWidget(RenderWidgetHost* widget);
+
+ // Returns the associated RenderWidgetHost.
+ virtual RenderWidgetHost* GetRenderWidgetHost() const = 0;
+
+ // Notifies the View that it has become visible.
+ virtual void DidBecomeSelected() = 0;
+
+ // Notifies the View that it has been hidden.
+ virtual void WasHidden() = 0;
+
+ // Tells the View to size itself to the specified size.
+ virtual void SetSize(const gfx::Size& size) = 0;
+
+ // Retrieves the HWND used to contain plugin HWNDs.
+ virtual HWND GetPluginHWND() = 0;
+
+ // Sends the specified mouse event to the renderer.
+ virtual void ForwardMouseEventToRenderer(UINT message,
+ WPARAM wparam,
+ LPARAM lparam) = 0;
+
+ // Actually set/take focus to/from the associated View component.
+ virtual void Focus() = 0;
+ virtual void Blur() = 0;
+
+ // Returns true if the View currently has the focus.
+ virtual bool HasFocus() = 0;
+
+ // Shows/hides the view.
+ virtual void Show() = 0;
+ virtual void Hide() = 0;
+
+ // Retrieve the bounds of the View, in screen coordinates.
+ virtual gfx::Rect GetViewBounds() const = 0;
+
+ // Sets the cursor to the one associated with the specified cursor_type
+ virtual void UpdateCursor(const WebCursor& cursor) = 0;
+
+ // Updates the displayed cursor to the current one.
+ virtual void UpdateCursorIfOverSelf() = 0;
+
+ // Indicates whether the page has finished loading.
+ virtual void SetIsLoading(bool is_loading) = 0;
+
+ // Enable or disable IME for the view.
+ virtual void IMEUpdateStatus(ViewHostMsg_ImeControl control,
+ const gfx::Rect& caret_rect) = 0;
+
+ // Informs the view that a portion of the widget's backing store was painted.
+ virtual void DidPaintRect(const gfx::Rect& rect) = 0;
+
+ // Informs the view that a portion of the widget's backing store was scrolled
+ // by dx pixels horizontally and dy pixels vertically.
+ virtual void DidScrollRect(
+ const gfx::Rect& rect, int dx, int dy) = 0;
+
+ // Notifies the View that the renderer has ceased to exist.
+ virtual void RendererGone() = 0;
+
+ // Tells the View to destroy itself.
+ virtual void Destroy() = 0;
+
+ // Tells the View that the tooltip text for the current mouse position over
+ // the page has changed.
+ virtual void SetTooltipText(const std::wstring& tooltip_text) = 0;
+
+ protected:
+ // Interface class only, do not construct.
+ RenderWidgetHostView() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostView);
+};
+
+#endif // CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_VIEW_H_
+
diff --git a/chrome/browser/renderer_host/render_widget_host_view_win.cc b/chrome/browser/renderer_host/render_widget_host_view_win.cc
new file mode 100644
index 0000000..f628809
--- /dev/null
+++ b/chrome/browser/renderer_host/render_widget_host_view_win.cc
@@ -0,0 +1,925 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/renderer_host/render_widget_host_view_win.h"
+
+#include "base/command_line.h"
+#include "base/gfx/gdi_util.h"
+#include "base/gfx/rect.h"
+#include "base/histogram.h"
+#include "base/win_util.h"
+#include "chrome/browser/browser_accessibility.h"
+#include "chrome/browser/browser_accessibility_manager.h"
+#include "chrome/browser/browser_trial.h"
+#include "chrome/browser/renderer_host/render_process_host.h"
+// TODO(beng): (Cleanup) we should not need to include this file... see comment
+// in |DidBecomeSelected|.
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/renderer_host/render_widget_host.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/l10n_util.h"
+#include "chrome/common/plugin_messages.h"
+#include "chrome/common/win_util.h"
+// Included for views::kReflectedMessage - TODO(beng): move this to win_util.h!
+#include "chrome/views/widget_win.h"
+#include "webkit/glue/plugins/plugin_constants_win.h"
+#include "webkit/glue/plugins/webplugin_delegate_impl.h"
+#include "webkit/glue/webcursor.h"
+
+using base::TimeDelta;
+using base::TimeTicks;
+
+namespace {
+
+// Tooltips will wrap after this width. Yes, wrap. Imagine that!
+const int kTooltipMaxWidthPixels = 300;
+
+// Maximum number of characters we allow in a tooltip.
+const int kMaxTooltipLength = 1024;
+
+// A callback function for EnumThreadWindows to enumerate and dismiss
+// any owned popop windows
+BOOL CALLBACK DismissOwnedPopups(HWND window, LPARAM arg) {
+ const HWND toplevel_hwnd = reinterpret_cast<HWND>(arg);
+
+ if (::IsWindowVisible(window)) {
+ const HWND owner = ::GetWindow(window, GW_OWNER);
+ if (toplevel_hwnd == owner) {
+ ::PostMessage(window, WM_CANCELMODE, 0, 0);
+ }
+ }
+
+ return TRUE;
+}
+
+} // namespace
+
+// RenderWidgetHostView --------------------------------------------------------
+
+// static
+RenderWidgetHostView* RenderWidgetHostView::CreateViewForWidget(
+ RenderWidgetHost* widget) {
+ return new RenderWidgetHostViewWin(widget);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// RenderWidgetHostViewWin, public:
+
+RenderWidgetHostViewWin::RenderWidgetHostViewWin(RenderWidgetHost* widget)
+ : render_widget_host_(widget),
+ track_mouse_leave_(false),
+ ime_notification_(false),
+ is_hidden_(false),
+ close_on_deactivate_(false),
+ tooltip_hwnd_(NULL),
+ tooltip_showing_(false),
+ shutdown_factory_(this),
+ parent_hwnd_(NULL),
+ is_loading_(false),
+ activatable_(true) {
+ render_widget_host_->set_view(this);
+ renderer_accessible_ =
+ CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableRendererAccessibility);
+}
+
+RenderWidgetHostViewWin::~RenderWidgetHostViewWin() {
+ ResetTooltip();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// RenderWidgetHostViewWin, RenderWidgetHostView implementation:
+
+RenderWidgetHost* RenderWidgetHostViewWin::GetRenderWidgetHost() const {
+ return render_widget_host_;
+}
+
+void RenderWidgetHostViewWin::DidBecomeSelected() {
+ if (!is_hidden_)
+ return;
+
+ is_hidden_ = false;
+ EnsureTooltip();
+ render_widget_host_->WasRestored();
+}
+
+void RenderWidgetHostViewWin::WasHidden() {
+ if (is_hidden_)
+ return;
+
+ // If we receive any more paint messages while we are hidden, we want to
+ // ignore them so we don't re-allocate the backing store. We will paint
+ // everything again when we become selected again.
+ is_hidden_ = true;
+
+ ResetTooltip();
+
+ // If we have a renderer, then inform it that we are being hidden so it can
+ // reduce its resource utilization.
+ render_widget_host_->WasHidden();
+
+ // TODO(darin): what about constrained windows? it doesn't look like they
+ // see a message when their parent is hidden. maybe there is something more
+ // generic we can do at the TabContents API level instead of relying on
+ // Windows messages.
+}
+
+void RenderWidgetHostViewWin::SetSize(const gfx::Size& size) {
+ if (is_hidden_)
+ return;
+
+ // No SWP_NOREDRAW as autofill popups can resize and the underneath window
+ // should redraw in that case.
+ UINT swp_flags = SWP_NOSENDCHANGING | SWP_NOOWNERZORDER | SWP_NOCOPYBITS |
+ SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_DEFERERASE;
+ SetWindowPos(NULL, 0, 0, size.width(), size.height(), swp_flags);
+ render_widget_host_->WasResized();
+ EnsureTooltip();
+}
+
+HWND RenderWidgetHostViewWin::GetPluginHWND() {
+ return m_hWnd;
+}
+
+void RenderWidgetHostViewWin::ForwardMouseEventToRenderer(UINT message,
+ WPARAM wparam,
+ LPARAM lparam) {
+ WebMouseEvent event(m_hWnd, message, wparam, lparam);
+ switch (event.type) {
+ case WebInputEvent::MOUSE_MOVE:
+ TrackMouseLeave(true);
+ break;
+ case WebInputEvent::MOUSE_LEAVE:
+ TrackMouseLeave(false);
+ break;
+ case WebInputEvent::MOUSE_DOWN:
+ SetCapture();
+ break;
+ case WebInputEvent::MOUSE_UP:
+ if (GetCapture() == m_hWnd)
+ ReleaseCapture();
+ break;
+ }
+
+ render_widget_host_->ForwardMouseEvent(event);
+
+ if (activatable_ && event.type == WebInputEvent::MOUSE_DOWN) {
+ // This is a temporary workaround for bug 765011 to get focus when the
+ // mouse is clicked. This happens after the mouse down event is sent to
+ // the renderer because normally Windows does a WM_SETFOCUS after
+ // WM_LBUTTONDOWN.
+ SetFocus();
+ }
+}
+
+void RenderWidgetHostViewWin::Focus() {
+ if (IsWindow())
+ SetFocus();
+}
+
+void RenderWidgetHostViewWin::Blur() {
+ views::FocusManager* focus_manager =
+ views::FocusManager::GetFocusManager(GetParent());
+ // We don't have a FocusManager if we are hidden.
+ if (focus_manager && render_widget_host_->CanBlur())
+ focus_manager->ClearFocus();
+}
+
+bool RenderWidgetHostViewWin::HasFocus() {
+ return ::GetFocus() == m_hWnd;
+}
+
+void RenderWidgetHostViewWin::Show() {
+ DCHECK(parent_hwnd_);
+ SetParent(parent_hwnd_);
+ ShowWindow(SW_SHOW);
+
+ DidBecomeSelected();
+}
+
+void RenderWidgetHostViewWin::Hide() {
+ if (::GetFocus() == m_hWnd)
+ ::SetFocus(NULL);
+ ShowWindow(SW_HIDE);
+ parent_hwnd_ = GetParent();
+ // Orphan the window so we stop receiving messages.
+ SetParent(NULL);
+
+ WasHidden();
+}
+
+gfx::Rect RenderWidgetHostViewWin::GetViewBounds() const {
+ CRect window_rect;
+ GetWindowRect(&window_rect);
+ return gfx::Rect(window_rect);
+}
+
+void RenderWidgetHostViewWin::UpdateCursor(const WebCursor& cursor) {
+ current_cursor_ = cursor;
+ UpdateCursorIfOverSelf();
+}
+
+void RenderWidgetHostViewWin::UpdateCursorIfOverSelf() {
+ static HCURSOR kCursorArrow = LoadCursor(NULL, IDC_ARROW);
+ static HCURSOR kCursorAppStarting = LoadCursor(NULL, IDC_APPSTARTING);
+ static HINSTANCE module_handle =
+ GetModuleHandle(chrome::kBrowserResourcesDll);
+
+ // We cannot pass in NULL as the module handle as this would only work for
+ // standard win32 cursors. We can also receive cursor types which are defined
+ // as webkit resources. We need to specify the module handle of chrome.dll
+ // while loading these cursors.
+ HCURSOR display_cursor = current_cursor_.GetCursor(module_handle);
+
+ // If a page is in the loading state, we want to show the Arrow+Hourglass
+ // cursor only when the current cursor is the ARROW cursor. In all other
+ // cases we should continue to display the current cursor.
+ if (is_loading_ && display_cursor == kCursorArrow)
+ display_cursor = kCursorAppStarting;
+
+ // If the mouse is over our HWND, then update the cursor state immediately.
+ CPoint pt;
+ GetCursorPos(&pt);
+ if (WindowFromPoint(pt) == m_hWnd)
+ SetCursor(display_cursor);
+}
+
+void RenderWidgetHostViewWin::SetIsLoading(bool is_loading) {
+ is_loading_ = is_loading;
+ UpdateCursorIfOverSelf();
+}
+
+void RenderWidgetHostViewWin::IMEUpdateStatus(ViewHostMsg_ImeControl control,
+ const gfx::Rect& caret_rect) {
+ if (control == IME_DISABLE) {
+ ime_input_.DisableIME(m_hWnd);
+ } else {
+ ime_input_.EnableIME(m_hWnd, caret_rect,
+ control == IME_COMPLETE_COMPOSITION);
+ }
+}
+
+BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lparam) {
+ if (!WebPluginDelegateImpl::IsPluginDelegateWindow(hwnd))
+ return TRUE;
+
+ gfx::Rect* rect = reinterpret_cast<gfx::Rect*>(lparam);
+ static UINT msg = RegisterWindowMessage(kPaintMessageName);
+ WPARAM wparam = rect->x() << 16 | rect->y();
+ lparam = rect->width() << 16 | rect->height();
+
+ // SendMessage gets the message across much quicker than PostMessage, since it
+ // doesn't get queued. When the plugin thread calls PeekMessage or other
+ // Win32 APIs, sent messages are dispatched automatically.
+ SendNotifyMessage(hwnd, msg, wparam, lparam);
+
+ return TRUE;
+}
+
+void RenderWidgetHostViewWin::Redraw(const gfx::Rect& rect) {
+ // Paint the invalid region synchronously. Our caller will not paint again
+ // until we return, so by painting to the screen here, we ensure effective
+ // rate-limiting of backing store updates. This helps a lot on pages that
+ // have animations or fairly expensive layout (e.g., google maps).
+ //
+ // We paint this window synchronously, however child windows (i.e. plugins)
+ // are painted asynchronously. By avoiding synchronous cross-process window
+ // message dispatching we allow scrolling to be smooth, and also avoid the
+ // browser process locking up if the plugin process is hung.
+ //
+ RedrawWindow(
+ &rect.ToRECT(), NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOCHILDREN);
+
+ // Send the invalid rect in screen coordinates.
+ gfx::Rect screen_rect = GetViewBounds();
+ gfx::Rect invalid_screen_rect = rect;
+ invalid_screen_rect.Offset(screen_rect.x(), screen_rect.y());
+
+ LPARAM lparam = reinterpret_cast<LPARAM>(&invalid_screen_rect);
+ EnumChildWindows(m_hWnd, EnumChildProc, lparam);
+}
+
+void RenderWidgetHostViewWin::DidPaintRect(const gfx::Rect& rect) {
+ if (is_hidden_)
+ return;
+
+ Redraw(rect);
+}
+
+void RenderWidgetHostViewWin::DidScrollRect(
+ const gfx::Rect& rect, int dx, int dy) {
+ if (is_hidden_)
+ return;
+
+ // We need to pass in SW_INVALIDATE to ScrollWindowEx. The MSDN
+ // documentation states that it only applies to the HRGN argument, which is
+ // wrong. Not passing in this flag does not invalidate the region which was
+ // scrolled from, thus causing painting issues.
+ RECT clip_rect = rect.ToRECT();
+ ScrollWindowEx(dx, dy, NULL, &clip_rect, NULL, NULL, SW_INVALIDATE);
+
+ RECT invalid_rect = {0};
+ GetUpdateRect(&invalid_rect);
+ Redraw(gfx::Rect(invalid_rect));
+}
+
+void RenderWidgetHostViewWin::RendererGone() {
+ // TODO(darin): keep this around, and draw sad-tab into it.
+ UpdateCursorIfOverSelf();
+ DestroyWindow();
+}
+
+void RenderWidgetHostViewWin::Destroy() {
+ // We've been told to destroy.
+ // By clearing close_on_deactivate_, we prevent further deactivations
+ // (caused by windows messages resulting from the DestroyWindow) from
+ // triggering further destructions. The deletion of this is handled by
+ // OnFinalMessage();
+ close_on_deactivate_ = false;
+ DestroyWindow();
+}
+
+void RenderWidgetHostViewWin::SetTooltipText(const std::wstring& tooltip_text) {
+ if (tooltip_text != tooltip_text_) {
+ tooltip_text_ = tooltip_text;
+
+ // Clamp the tooltip length to kMaxTooltipLength so that we don't
+ // accidentally DOS the user with a mega tooltip (since Windows doesn't seem
+ // to do this itself).
+ if (tooltip_text_.length() > kMaxTooltipLength)
+ tooltip_text_ = tooltip_text_.substr(0, kMaxTooltipLength);
+
+ // Need to check if the tooltip is already showing so that we don't
+ // immediately show the tooltip with no delay when we move the mouse from
+ // a region with no tooltip to a region with a tooltip.
+ if (::IsWindow(tooltip_hwnd_) && tooltip_showing_) {
+ ::SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
+ ::SendMessage(tooltip_hwnd_, TTM_POPUP, 0, 0);
+ }
+ } else {
+ // Make sure the tooltip gets closed after TTN_POP gets sent. For some
+ // reason this doesn't happen automatically, so moving the mouse around
+ // within the same link/image/etc doesn't cause the tooltip to re-appear.
+ if (!tooltip_showing_) {
+ if (::IsWindow(tooltip_hwnd_))
+ ::SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// RenderWidgetHostViewWin, private:
+
+LRESULT RenderWidgetHostViewWin::OnCreate(CREATESTRUCT* create_struct) {
+ // Call the WM_INPUTLANGCHANGE message handler to initialize the input locale
+ // of a browser process.
+ OnInputLangChange(0, 0);
+ return 0;
+}
+
+void RenderWidgetHostViewWin::OnActivate(UINT action, BOOL minimized,
+ HWND window) {
+ // If the container is a popup, clicking elsewhere on screen should close the
+ // popup.
+ if (close_on_deactivate_ && action == WA_INACTIVE) {
+ // Send a windows message so that any derived classes
+ // will get a change to override the default handling
+ SendMessage(WM_CANCELMODE);
+ }
+}
+
+void RenderWidgetHostViewWin::OnDestroy() {
+ ResetTooltip();
+ TrackMouseLeave(false);
+}
+
+void RenderWidgetHostViewWin::OnPaint(HDC dc) {
+ DCHECK(render_widget_host_->process()->channel());
+
+ CPaintDC paint_dc(m_hWnd);
+ HBRUSH white_brush = reinterpret_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));
+
+ RenderWidgetHost::BackingStore* backing_store =
+ render_widget_host_->GetBackingStore();
+
+ if (backing_store) {
+ gfx::Rect damaged_rect(paint_dc.m_ps.rcPaint);
+
+ gfx::Rect bitmap_rect(
+ 0, 0, backing_store->size().width(), backing_store->size().height());
+
+ gfx::Rect paint_rect = bitmap_rect.Intersect(damaged_rect);
+ if (!paint_rect.IsEmpty()) {
+ BitBlt(paint_dc.m_hDC,
+ paint_rect.x(),
+ paint_rect.y(),
+ paint_rect.width(),
+ paint_rect.height(),
+ backing_store->dc(),
+ paint_rect.x(),
+ paint_rect.y(),
+ SRCCOPY);
+ }
+
+ // Fill the remaining portion of the damaged_rect with white
+ if (damaged_rect.right() > bitmap_rect.right()) {
+ RECT r;
+ r.left = std::max(bitmap_rect.right(), damaged_rect.x());
+ r.right = damaged_rect.right();
+ r.top = damaged_rect.y();
+ r.bottom = std::min(bitmap_rect.bottom(), damaged_rect.bottom());
+ paint_dc.FillRect(&r, white_brush);
+ }
+ if (damaged_rect.bottom() > bitmap_rect.bottom()) {
+ RECT r;
+ r.left = damaged_rect.x();
+ r.right = damaged_rect.right();
+ r.top = std::max(bitmap_rect.bottom(), damaged_rect.y());
+ r.bottom = damaged_rect.bottom();
+ paint_dc.FillRect(&r, white_brush);
+ }
+ if (!whiteout_start_time_.is_null()) {
+ TimeDelta whiteout_duration = TimeTicks::Now() - whiteout_start_time_;
+
+ // If field trial is active, report results in special histogram.
+ static scoped_refptr<FieldTrial> trial(
+ FieldTrialList::Find(BrowserTrial::kMemoryModelFieldTrial));
+ if (trial.get()) {
+ if (trial->boolean_value())
+ UMA_HISTOGRAM_TIMES(L"MPArch.RWHH_WhiteoutDuration_trial_high_memory",
+ whiteout_duration);
+ else
+ UMA_HISTOGRAM_TIMES(L"MPArch.RWHH_WhiteoutDuration_trial_med_memory",
+ whiteout_duration);
+ } else {
+ UMA_HISTOGRAM_TIMES(L"MPArch.RWHH_WhiteoutDuration", whiteout_duration);
+ }
+
+ // Reset the start time to 0 so that we start recording again the next
+ // time the backing store is NULL...
+ whiteout_start_time_ = TimeTicks();
+ }
+ } else {
+ paint_dc.FillRect(&paint_dc.m_ps.rcPaint, white_brush);
+ if (whiteout_start_time_.is_null())
+ whiteout_start_time_ = TimeTicks::Now();
+ }
+}
+
+void RenderWidgetHostViewWin::OnNCPaint(HRGN update_region) {
+ // Do nothing. This suppresses the resize corner that Windows would
+ // otherwise draw for us.
+}
+
+LRESULT RenderWidgetHostViewWin::OnEraseBkgnd(HDC dc) {
+ return 1;
+}
+
+LRESULT RenderWidgetHostViewWin::OnSetCursor(HWND window, UINT hittest_code,
+ UINT mouse_message_id) {
+ UpdateCursorIfOverSelf();
+ return 0;
+}
+
+void RenderWidgetHostViewWin::OnSetFocus(HWND window) {
+ render_widget_host_->Focus();
+}
+
+void RenderWidgetHostViewWin::OnKillFocus(HWND window) {
+ render_widget_host_->Blur();
+}
+
+void RenderWidgetHostViewWin::OnCaptureChanged(HWND window) {
+ render_widget_host_->LostCapture();
+}
+
+void RenderWidgetHostViewWin::OnCancelMode() {
+ render_widget_host_->LostCapture();
+
+ if (close_on_deactivate_ && shutdown_factory_.empty()) {
+ // Dismiss popups and menus. We do this asynchronously to avoid changing
+ // activation within this callstack, which may interfere with another window
+ // being activated. We can synchronously hide the window, but we need to
+ // not change activation while doing so.
+ SetWindowPos(NULL, 0, 0, 0, 0,
+ SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOMOVE |
+ SWP_NOREPOSITION | SWP_NOSIZE | SWP_NOZORDER);
+ MessageLoop::current()->PostTask(FROM_HERE,
+ shutdown_factory_.NewRunnableMethod(
+ &RenderWidgetHostViewWin::ShutdownHost));
+ }
+}
+
+void RenderWidgetHostViewWin::OnInputLangChange(DWORD character_set,
+ HKL input_language_id) {
+ // Send the given Locale ID to the ImeInput object and retrieves whether
+ // or not the current input context has IMEs.
+ // If the current input context has IMEs, a browser process has to send a
+ // request to a renderer process that it needs status messages about
+ // the focused edit control from the renderer process.
+ // On the other hand, if the current input context does not have IMEs, the
+ // browser process also has to send a request to the renderer process that
+ // it does not need the status messages any longer.
+ // To minimize the number of this notification request, we should check if
+ // the browser process is actually retrieving the status messages (this
+ // state is stored in ime_notification_) and send a request only if the
+ // browser process has to update this status, its details are listed below:
+ // * If a browser process is not retrieving the status messages,
+ // (i.e. ime_notification_ == false),
+ // send this request only if the input context does have IMEs,
+ // (i.e. ime_status == true);
+ // When it successfully sends the request, toggle its notification status,
+ // (i.e.ime_notification_ = !ime_notification_ = true).
+ // * If a browser process is retrieving the status messages
+ // (i.e. ime_notification_ == true),
+ // send this request only if the input context does not have IMEs,
+ // (i.e. ime_status == false).
+ // When it successfully sends the request, toggle its notification status,
+ // (i.e.ime_notification_ = !ime_notification_ = false).
+ // To analyze the above actions, we can optimize them into the ones
+ // listed below:
+ // 1 Sending a request only if ime_status_ != ime_notification_, and;
+ // 2 Copying ime_status to ime_notification_ if it sends the request
+ // successfully (because Action 1 shows ime_status = !ime_notification_.)
+ bool ime_status = ime_input_.SetInputLanguage();
+ if (ime_status != ime_notification_) {
+ if (Send(new ViewMsg_ImeSetInputMode(render_widget_host_->routing_id(),
+ ime_status))) {
+ ime_notification_ = ime_status;
+ }
+ }
+}
+
+void RenderWidgetHostViewWin::OnThemeChanged() {
+ render_widget_host_->SystemThemeChanged();
+}
+
+LRESULT RenderWidgetHostViewWin::OnNotify(int w_param, NMHDR* header) {
+ if (tooltip_hwnd_ == NULL)
+ return 0;
+
+ switch (header->code) {
+ case TTN_GETDISPINFO: {
+ NMTTDISPINFOW* tooltip_info = reinterpret_cast<NMTTDISPINFOW*>(header);
+ tooltip_info->szText[0] = L'\0';
+ tooltip_info->lpszText = const_cast<wchar_t*>(tooltip_text_.c_str());
+ ::SendMessage(
+ tooltip_hwnd_, TTM_SETMAXTIPWIDTH, 0, kTooltipMaxWidthPixels);
+ SetMsgHandled(TRUE);
+ break;
+ }
+ case TTN_POP:
+ tooltip_showing_ = false;
+ SetMsgHandled(TRUE);
+ break;
+ case TTN_SHOW:
+ tooltip_showing_ = true;
+ SetMsgHandled(TRUE);
+ break;
+ }
+ return 0;
+}
+
+LRESULT RenderWidgetHostViewWin::OnImeSetContext(
+ UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) {
+ // We need status messages about the focused input control from a
+ // renderer process when:
+ // * the current input context has IMEs, and;
+ // * an application is activated.
+ // This seems to tell we should also check if the current input context has
+ // IMEs before sending a request, however, this WM_IME_SETCONTEXT is
+ // fortunately sent to an application only while the input context has IMEs.
+ // Therefore, we just start/stop status messages according to the activation
+ // status of this application without checks.
+ bool activated = (wparam == TRUE);
+ if (Send(new ViewMsg_ImeSetInputMode(
+ render_widget_host_->routing_id(), activated))) {
+ ime_notification_ = activated;
+ }
+
+ if (ime_notification_)
+ ime_input_.CreateImeWindow(m_hWnd);
+
+ ime_input_.CleanupComposition(m_hWnd);
+ ime_input_.SetImeWindowStyle(m_hWnd, message, wparam, lparam, &handled);
+ return 0;
+}
+
+LRESULT RenderWidgetHostViewWin::OnImeStartComposition(
+ UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) {
+ // Reset the composition status and create IME windows.
+ ime_input_.CreateImeWindow(m_hWnd);
+ ime_input_.ResetComposition(m_hWnd);
+ // We have to prevent WTL from calling ::DefWindowProc() because the function
+ // calls ::ImmSetCompositionWindow() and ::ImmSetCandidateWindow() to
+ // over-write the position of IME windows.
+ handled = TRUE;
+ return 0;
+}
+
+LRESULT RenderWidgetHostViewWin::OnImeComposition(
+ UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) {
+ // At first, update the position of the IME window.
+ ime_input_.UpdateImeWindow(m_hWnd);
+
+ // Retrieve the result string and its attributes of the ongoing composition
+ // and send it to a renderer process.
+ ImeComposition composition;
+ if (ime_input_.GetResult(m_hWnd, lparam, &composition)) {
+ Send(new ViewMsg_ImeSetComposition(render_widget_host_->routing_id(),
+ composition.string_type,
+ composition.cursor_position,
+ composition.target_start,
+ composition.target_end,
+ composition.ime_string));
+ ime_input_.ResetComposition(m_hWnd);
+ // Fall though and try reading the composition string.
+ // Japanese IMEs send a message containing both GCS_RESULTSTR and
+ // GCS_COMPSTR, which means an ongoing composition has been finished
+ // by the start of another composition.
+ }
+ // Retrieve the composition string and its attributes of the ongoing
+ // composition and send it to a renderer process.
+ if (ime_input_.GetComposition(m_hWnd, lparam, &composition)) {
+ Send(new ViewMsg_ImeSetComposition(render_widget_host_->routing_id(),
+ composition.string_type,
+ composition.cursor_position,
+ composition.target_start,
+ composition.target_end,
+ composition.ime_string));
+ }
+ // We have to prevent WTL from calling ::DefWindowProc() because we do not
+ // want for the IMM (Input Method Manager) to send WM_IME_CHAR messages.
+ handled = TRUE;
+ return 0;
+}
+
+LRESULT RenderWidgetHostViewWin::OnImeEndComposition(
+ UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled) {
+ if (ime_input_.is_composing()) {
+ // A composition has been ended while there is an ongoing composition,
+ // i.e. the ongoing composition has been canceled.
+ // We need to reset the composition status both of the ImeInput object and
+ // of the renderer process.
+ std::wstring empty_string;
+ Send(new ViewMsg_ImeSetComposition(render_widget_host_->routing_id(),
+ 0, -1, -1, -1, empty_string));
+ ime_input_.ResetComposition(m_hWnd);
+ }
+ ime_input_.DestroyImeWindow(m_hWnd);
+ // Let WTL call ::DefWindowProc() and release its resources.
+ handled = FALSE;
+ return 0;
+}
+
+LRESULT RenderWidgetHostViewWin::OnMouseEvent(UINT message, WPARAM wparam,
+ LPARAM lparam, BOOL& handled) {
+ handled = TRUE;
+
+ if (::IsWindow(tooltip_hwnd_)) {
+ // Forward mouse events through to the tooltip window
+ MSG msg;
+ msg.hwnd = m_hWnd;
+ msg.message = message;
+ msg.wParam = wparam;
+ msg.lParam = lparam;
+ SendMessage(tooltip_hwnd_, TTM_RELAYEVENT, NULL,
+ reinterpret_cast<LPARAM>(&msg));
+ }
+
+ // TODO(jcampan): I am not sure if we should forward the message to the
+ // WebContents first in the case of popups. If we do, we would need to
+ // convert the click from the popup window coordinates to the WebContents'
+ // window coordinates. For now we don't forward the message in that case to
+ // address bug #907474.
+ // Note: GetParent() on popup windows returns the top window and not the
+ // parent the window was created with (the parent and the owner of the popup
+ // is the first non-child view of the view that was specified to the create
+ // call). So the WebContents window would have to be specified to the
+ // RenderViewHostHWND as there is no way to retrieve it from the HWND.
+ if (!close_on_deactivate_) { // Don't forward if the container is a popup.
+ switch (message) {
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_MOUSEMOVE:
+ case WM_MOUSELEAVE:
+ case WM_RBUTTONDOWN: {
+ // Give the WebContents first crack at the message. It may want to
+ // prevent forwarding to the renderer if some higher level browser
+ // functionality is invoked.
+ if (SendMessage(GetParent(), message, wparam, lparam) != 0)
+ return 1;
+ }
+ }
+ }
+
+ ForwardMouseEventToRenderer(message, wparam, lparam);
+ return 0;
+}
+
+LRESULT RenderWidgetHostViewWin::OnKeyEvent(UINT message, WPARAM wparam,
+ LPARAM lparam, BOOL& handled) {
+ handled = TRUE;
+
+ // If we are a pop-up, forward tab related messages to our parent HWND, so
+ // that we are dismissed appropriately and so that the focus advance in our
+ // parent.
+ // TODO(jcampan): http://b/issue?id=1192881 Could be abstracted in the
+ // FocusManager.
+ if (close_on_deactivate_ &&
+ (((message == WM_KEYDOWN || message == WM_KEYUP) && (wparam == VK_TAB)) ||
+ (message == WM_CHAR && wparam == L'\t'))) {
+ DCHECK(parent_hwnd_);
+ // First close the pop-up.
+ SendMessage(WM_CANCELMODE);
+ // Then move the focus by forwarding the tab key to the parent.
+ return ::SendMessage(parent_hwnd_, message, wparam, lparam);
+ }
+
+ render_widget_host_->ForwardKeyboardEvent(
+ WebKeyboardEvent(m_hWnd, message, wparam, lparam));
+ return 0;
+}
+
+LRESULT RenderWidgetHostViewWin::OnWheelEvent(UINT message, WPARAM wparam,
+ LPARAM lparam, BOOL& handled) {
+ // Workaround for Thinkpad mousewheel driver. We get mouse wheel/scroll
+ // messages even if we are not in the foreground. So here we check if
+ // we have any owned popup windows in the foreground and dismiss them.
+ if (m_hWnd != GetForegroundWindow()) {
+ HWND toplevel_hwnd = ::GetAncestor(m_hWnd, GA_ROOT);
+ EnumThreadWindows(
+ GetCurrentThreadId(),
+ DismissOwnedPopups,
+ reinterpret_cast<LPARAM>(toplevel_hwnd));
+ }
+
+ // This is a bit of a hack, but will work for now since we don't want to
+ // pollute this object with WebContents-specific functionality...
+ bool handled_by_webcontents = false;
+ if (GetParent()) {
+ // Use a special reflected message to break recursion. If we send
+ // WM_MOUSEWHEEL, the focus manager subclass of web contents will
+ // route it back here.
+ MSG new_message = {0};
+ new_message.hwnd = m_hWnd;
+ new_message.message = message;
+ new_message.wParam = wparam;
+ new_message.lParam = lparam;
+
+ handled_by_webcontents =
+ !!::SendMessage(GetParent(), views::kReflectedMessage, 0,
+ reinterpret_cast<LPARAM>(&new_message));
+ }
+
+ if (!handled_by_webcontents) {
+ render_widget_host_->ForwardWheelEvent(
+ WebMouseWheelEvent(m_hWnd, message, wparam, lparam));
+ }
+ handled = TRUE;
+ return 0;
+}
+
+LRESULT RenderWidgetHostViewWin::OnMouseActivate(UINT, WPARAM, LPARAM,
+ BOOL& handled) {
+ if (!activatable_)
+ return MA_NOACTIVATE;
+
+ HWND focus_window = GetFocus();
+ if (!::IsWindow(focus_window) || !IsChild(focus_window)) {
+ // We handle WM_MOUSEACTIVATE to set focus to the underlying plugin
+ // child window. This is to ensure that keyboard events are received
+ // by the plugin. The correct way to fix this would be send over
+ // an event to the renderer which would then eventually send over
+ // a setFocus call to the plugin widget. This would ensure that
+ // the renderer (webkit) knows about the plugin widget receiving
+ // focus.
+ // TODO(iyengar) Do the right thing as per the above comment.
+ POINT cursor_pos = {0};
+ ::GetCursorPos(&cursor_pos);
+ ::ScreenToClient(m_hWnd, &cursor_pos);
+ HWND child_window = ::RealChildWindowFromPoint(m_hWnd, cursor_pos);
+ if (::IsWindow(child_window)) {
+ ::SetFocus(child_window);
+ return MA_NOACTIVATE;
+ }
+ }
+ handled = FALSE;
+ return MA_ACTIVATE;
+}
+
+LRESULT RenderWidgetHostViewWin::OnGetObject(UINT message, WPARAM wparam,
+ LPARAM lparam, BOOL& handled) {
+ LRESULT reference_result = static_cast<LRESULT>(0L);
+ // TODO(jcampan): http://b/issue?id=1432077 Disabling accessibility in the
+ // renderer is a temporary work-around until that bug is fixed.
+ if (!renderer_accessible_)
+ return reference_result;
+
+ // Accessibility readers will send an OBJID_CLIENT message.
+ if (OBJID_CLIENT == lparam) {
+ // If our MSAA DOM root is already created, reuse that pointer. Otherwise,
+ // create a new one.
+ if (!browser_accessibility_root_) {
+ CComObject<BrowserAccessibility>* accessibility = NULL;
+
+ if (!SUCCEEDED(CComObject<BrowserAccessibility>::CreateInstance(
+ &accessibility)) || !accessibility) {
+ // Return with failure.
+ return static_cast<LRESULT>(0L);
+ }
+
+ CComPtr<IAccessible> accessibility_comptr(accessibility);
+
+ // Root id is always 0, to distinguish this particular instance when
+ // mapping to the render-side IAccessible.
+ accessibility->set_iaccessible_id(0);
+
+ // Set the unique member variables of this particular process.
+ accessibility->set_instance_id(
+ BrowserAccessibilityManager::GetInstance()->
+ SetMembers(accessibility, m_hWnd, render_widget_host_));
+
+ // All is well, assign the temp instance to the class smart pointer.
+ browser_accessibility_root_.Attach(accessibility_comptr.Detach());
+
+ if (!browser_accessibility_root_) {
+ // Paranoia check. Return with failure.
+ NOTREACHED();
+ return static_cast<LRESULT>(0L);
+ }
+
+ // Notify that an instance of IAccessible was allocated for m_hWnd.
+ ::NotifyWinEvent(EVENT_OBJECT_CREATE, m_hWnd, OBJID_CLIENT,
+ CHILDID_SELF);
+ }
+
+ // Create a reference to ViewAccessibility that MSAA will marshall
+ // to the client.
+ reference_result = LresultFromObject(IID_IAccessible, wparam,
+ static_cast<IAccessible*>(browser_accessibility_root_));
+ }
+ return reference_result;
+}
+
+void RenderWidgetHostViewWin::OnFinalMessage(HWND window) {
+ render_widget_host_->ViewDestroyed();
+ delete this;
+}
+
+void RenderWidgetHostViewWin::TrackMouseLeave(bool track) {
+ if (track == track_mouse_leave_)
+ return;
+ track_mouse_leave_ = track;
+
+ DCHECK(m_hWnd);
+
+ TRACKMOUSEEVENT tme;
+ tme.cbSize = sizeof(TRACKMOUSEEVENT);
+ tme.dwFlags = TME_LEAVE;
+ if (!track_mouse_leave_)
+ tme.dwFlags |= TME_CANCEL;
+ tme.hwndTrack = m_hWnd;
+
+ TrackMouseEvent(&tme);
+}
+
+bool RenderWidgetHostViewWin::Send(IPC::Message* message) {
+ return render_widget_host_->Send(message);
+}
+
+void RenderWidgetHostViewWin::EnsureTooltip() {
+ UINT message = TTM_NEWTOOLRECT;
+
+ TOOLINFO ti;
+ ti.cbSize = sizeof(ti);
+ ti.hwnd = m_hWnd;
+ ti.uId = 0;
+ if (!::IsWindow(tooltip_hwnd_)) {
+ message = TTM_ADDTOOL;
+ tooltip_hwnd_ = CreateWindowEx(
+ WS_EX_TRANSPARENT | l10n_util::GetExtendedTooltipStyles(),
+ TOOLTIPS_CLASS, NULL, TTS_NOPREFIX, 0, 0, 0, 0, m_hWnd, NULL,
+ NULL, NULL);
+ ti.uFlags = TTF_TRANSPARENT;
+ ti.lpszText = LPSTR_TEXTCALLBACK;
+ }
+
+ CRect cr;
+ GetClientRect(&ti.rect);
+ SendMessage(tooltip_hwnd_, message, NULL, reinterpret_cast<LPARAM>(&ti));
+}
+
+void RenderWidgetHostViewWin::ResetTooltip() {
+ if (::IsWindow(tooltip_hwnd_))
+ ::DestroyWindow(tooltip_hwnd_);
+ tooltip_hwnd_ = NULL;
+}
+
+void RenderWidgetHostViewWin::ShutdownHost() {
+ shutdown_factory_.RevokeAll();
+ render_widget_host_->Shutdown();
+ // Do not touch any members at this point, |this| has been deleted.
+}
diff --git a/chrome/browser/renderer_host/render_widget_host_view_win.h b/chrome/browser/renderer_host/render_widget_host_view_win.h
new file mode 100644
index 0000000..a735ab0
--- /dev/null
+++ b/chrome/browser/renderer_host/render_widget_host_view_win.h
@@ -0,0 +1,283 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_VIEW_WIN_H_
+#define CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_VIEW_WIN_H_
+
+#include <atlbase.h>
+#include <atlapp.h>
+#include <atlcrack.h>
+#include <atlmisc.h>
+
+#include "base/basictypes.h"
+#include "base/gfx/size.h"
+#include "base/scoped_handle.h"
+#include "base/shared_memory.h"
+#include "base/task.h"
+#include "chrome/browser/ime_input.h"
+#include "chrome/browser/renderer_host/render_widget_host_view.h"
+#include "chrome/common/render_messages.h"
+#include "chrome/views/focus_manager.h"
+
+namespace gfx {
+class Rect;
+}
+namespace IPC {
+class Message;
+}
+class RenderWidgetHost;
+class WebMouseEvent;
+class WebCursor;
+
+typedef CWinTraits<WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0>
+ RenderWidgetHostHWNDTraits;
+
+static const wchar_t* const kRenderWidgetHostHWNDClass =
+ L"Chrome_RenderWidgetHostHWND";
+
+///////////////////////////////////////////////////////////////////////////////
+// RenderWidgetHostViewWin
+//
+// An object representing the "View" of a rendered web page. This object is
+// responsible for displaying the content of the web page, receiving windows
+// messages, and containing plugins HWNDs. It is the implementation of the
+// RenderWidgetHostView that the cross-platform RenderWidgetHost object uses
+// to display the data.
+//
+// Comment excerpted from render_widget_host.h:
+//
+// "The lifetime of the RenderWidgetHostHWND is tied to the render process.
+// If the render process dies, the RenderWidgetHostHWND goes away and all
+// references to it must become NULL."
+//
+class RenderWidgetHostViewWin :
+ public CWindowImpl<RenderWidgetHostViewWin,
+ CWindow,
+ RenderWidgetHostHWNDTraits>,
+ public RenderWidgetHostView {
+ public:
+ // The view will associate itself with the given widget.
+ explicit RenderWidgetHostViewWin(RenderWidgetHost* widget);
+ virtual ~RenderWidgetHostViewWin();
+
+ void set_close_on_deactivate(bool close_on_deactivate) {
+ close_on_deactivate_ = close_on_deactivate;
+ }
+
+ void set_activatable(bool activatable) {
+ activatable_ = activatable;
+ }
+ bool activatable() const { return activatable_; }
+
+ void set_parent_hwnd(HWND parent) { parent_hwnd_ = parent; }
+
+ DECLARE_WND_CLASS_EX(kRenderWidgetHostHWNDClass, CS_DBLCLKS, 0);
+
+ BEGIN_MSG_MAP(RenderWidgetHostHWND)
+ MSG_WM_CREATE(OnCreate)
+ MSG_WM_ACTIVATE(OnActivate)
+ MSG_WM_DESTROY(OnDestroy)
+ MSG_WM_PAINT(OnPaint)
+ MSG_WM_NCPAINT(OnNCPaint)
+ MSG_WM_ERASEBKGND(OnEraseBkgnd)
+ MSG_WM_SETCURSOR(OnSetCursor)
+ MSG_WM_SETFOCUS(OnSetFocus)
+ MSG_WM_KILLFOCUS(OnKillFocus)
+ MSG_WM_CAPTURECHANGED(OnCaptureChanged)
+ MSG_WM_CANCELMODE(OnCancelMode)
+ MSG_WM_INPUTLANGCHANGE(OnInputLangChange)
+ MSG_WM_THEMECHANGED(OnThemeChanged)
+ MSG_WM_NOTIFY(OnNotify)
+ MESSAGE_HANDLER(WM_IME_SETCONTEXT, OnImeSetContext)
+ MESSAGE_HANDLER(WM_IME_STARTCOMPOSITION, OnImeStartComposition)
+ MESSAGE_HANDLER(WM_IME_COMPOSITION, OnImeComposition)
+ MESSAGE_HANDLER(WM_IME_ENDCOMPOSITION, OnImeEndComposition)
+ MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseEvent)
+ MESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseEvent)
+ MESSAGE_HANDLER(WM_LBUTTONDOWN, OnMouseEvent)
+ MESSAGE_HANDLER(WM_MBUTTONDOWN, OnMouseEvent)
+ MESSAGE_HANDLER(WM_RBUTTONDOWN, OnMouseEvent)
+ MESSAGE_HANDLER(WM_LBUTTONUP, OnMouseEvent)
+ MESSAGE_HANDLER(WM_MBUTTONUP, OnMouseEvent)
+ MESSAGE_HANDLER(WM_RBUTTONUP, OnMouseEvent)
+ MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnMouseEvent)
+ MESSAGE_HANDLER(WM_MBUTTONDBLCLK, OnMouseEvent)
+ MESSAGE_HANDLER(WM_RBUTTONDBLCLK, OnMouseEvent)
+ MESSAGE_HANDLER(WM_SYSKEYDOWN, OnKeyEvent)
+ MESSAGE_HANDLER(WM_SYSKEYUP, OnKeyEvent)
+ MESSAGE_HANDLER(WM_KEYDOWN, OnKeyEvent)
+ MESSAGE_HANDLER(WM_KEYUP, OnKeyEvent)
+ MESSAGE_HANDLER(WM_MOUSEWHEEL, OnWheelEvent)
+ MESSAGE_HANDLER(WM_MOUSEHWHEEL, OnWheelEvent)
+ MESSAGE_HANDLER(WM_HSCROLL, OnWheelEvent)
+ MESSAGE_HANDLER(WM_VSCROLL, OnWheelEvent)
+ MESSAGE_HANDLER(WM_CHAR, OnKeyEvent)
+ MESSAGE_HANDLER(WM_SYSCHAR, OnKeyEvent)
+ MESSAGE_HANDLER(WM_IME_CHAR, OnKeyEvent)
+ MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate)
+ MESSAGE_HANDLER(WM_GETOBJECT, OnGetObject)
+ END_MSG_MAP()
+
+ // Implementation of RenderWidgetHostView:
+ virtual RenderWidgetHost* GetRenderWidgetHost() const;
+ virtual void DidBecomeSelected();
+ virtual void WasHidden();
+ virtual void SetSize(const gfx::Size& size);
+ virtual HWND GetPluginHWND();
+ virtual void ForwardMouseEventToRenderer(UINT message,
+ WPARAM wparam,
+ LPARAM lparam);
+ virtual void Focus();
+ virtual void Blur();
+ virtual bool HasFocus();
+ virtual void Show();
+ virtual void Hide();
+ virtual gfx::Rect GetViewBounds() const;
+ virtual void UpdateCursor(const WebCursor& cursor);
+ virtual void UpdateCursorIfOverSelf();
+ virtual void SetIsLoading(bool is_loading);
+ virtual void IMEUpdateStatus(ViewHostMsg_ImeControl control,
+ const gfx::Rect& caret_rect);
+ virtual void DidPaintRect(const gfx::Rect& rect);
+ virtual void DidScrollRect(const gfx::Rect& rect, int dx, int dy);
+ virtual void RendererGone();
+ virtual void Destroy();
+ virtual void SetTooltipText(const std::wstring& tooltip_text);
+
+ protected:
+ // Windows Message Handlers
+ LRESULT OnCreate(CREATESTRUCT* create_struct);
+ void OnActivate(UINT, BOOL, HWND);
+ void OnDestroy();
+ void OnPaint(HDC dc);
+ void OnNCPaint(HRGN update_region);
+ LRESULT OnEraseBkgnd(HDC dc);
+ LRESULT OnSetCursor(HWND window, UINT hittest_code, UINT mouse_message_id);
+ void OnSetFocus(HWND window);
+ void OnKillFocus(HWND window);
+ void OnCaptureChanged(HWND window);
+ void OnCancelMode();
+ void OnInputLangChange(DWORD character_set, HKL input_language_id);
+ void OnThemeChanged();
+ LRESULT OnNotify(int w_param, NMHDR* header);
+ LRESULT OnImeSetContext(
+ UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled);
+ LRESULT OnImeStartComposition(
+ UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled);
+ LRESULT OnImeComposition(
+ UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled);
+ LRESULT OnImeEndComposition(
+ UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled);
+ LRESULT OnMouseEvent(
+ UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled);
+ LRESULT OnKeyEvent(
+ UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled);
+ LRESULT OnWheelEvent(
+ UINT message, WPARAM wparam, LPARAM lparam, BOOL& handled);
+ LRESULT OnMouseActivate(UINT, WPARAM, LPARAM, BOOL& handled);
+ // Handle MSAA requests for accessibility information.
+ LRESULT OnGetObject(UINT message, WPARAM wparam, LPARAM lparam,
+ BOOL& handled);
+ // Handle vertical scrolling
+ LRESULT OnVScroll(int code, short position, HWND scrollbar_control);
+ // Handle horizontal scrolling
+ LRESULT OnHScroll(int code, short position, HWND scrollbar_control);
+
+ void OnFinalMessage(HWND window);
+
+ private:
+ // Tells Windows that we want to hear about mouse exit messages.
+ void TrackMouseLeave(bool start_tracking);
+
+ // Sends a message to the RenderView in the renderer process.
+ bool Send(IPC::Message* message);
+
+ // Set the tooltip region to the size of the window, creating the tooltip
+ // hwnd if it has not been created yet.
+ void EnsureTooltip();
+
+ // Tooltips become invalid when the root ancestor changes. When the View
+ // becomes hidden, this method is called to reset the tooltip.
+ void ResetTooltip();
+
+ // Synthesize mouse wheel event.
+ LRESULT SynthesizeMouseWheel(bool is_vertical, int scroll_code,
+ short scroll_position);
+
+ // Shuts down the render_widget_host_. This is a separate function so we can
+ // invoke it from the message loop.
+ void ShutdownHost();
+
+ // Redraws the window synchronously, and any child windows (i.e. plugins)
+ // asynchronously.
+ void Redraw(const gfx::Rect& invalid_rect);
+
+ // The associated Model.
+ RenderWidgetHost* render_widget_host_;
+
+ // The cursor for the page. This is passed up from the renderer.
+ WebCursor current_cursor_;
+
+ // Indicates if the page is loading.
+ bool is_loading_;
+
+ // true if we are currently tracking WM_MOUSEEXIT messages.
+ bool track_mouse_leave_;
+
+ // Wrapper class for IME input.
+ // (See "chrome/browser/ime_input.h" for its details.)
+ ImeInput ime_input_;
+
+ // Represents whether or not this browser process is receiving status
+ // messages about the focused edit control from a renderer process.
+ bool ime_notification_;
+
+ // true if the View is not visible.
+ bool is_hidden_;
+
+ // true if the View should be closed when its HWND is deactivated (used to
+ // support SELECT popups which are closed when they are deactivated).
+ bool close_on_deactivate_;
+
+ // Tooltips
+ // The text to be shown in the tooltip, supplied by the renderer.
+ std::wstring tooltip_text_;
+ // The tooltip control hwnd
+ HWND tooltip_hwnd_;
+ // Whether or not a tooltip is currently visible. We use this to track
+ // whether or not we want to force-close the tooltip when we receive mouse
+ // move notifications from the renderer. See comment in OnMsgSetTooltipText.
+ bool tooltip_showing_;
+
+ // Factory used to safely scope delayed calls to ShutdownHost().
+ ScopedRunnableMethodFactory<RenderWidgetHostViewWin> shutdown_factory_;
+
+ // Our parent HWND. We keep a reference to it as we SetParent(NULL) when
+ // hidden to prevent getting messages (Paint, Resize...), and we reattach
+ // when shown again.
+ HWND parent_hwnd_;
+
+ // Instance of accessibility information for the root of the MSAA
+ // tree representation of the WebKit render tree.
+ CComPtr<IAccessible> browser_accessibility_root_;
+
+ // The time at which this view started displaying white pixels as a result of
+ // not having anything to paint (empty backing store from renderer). This
+ // value returns true for is_null() if we are not recording whiteout times.
+ base::TimeTicks whiteout_start_time_;
+
+ // Whether the window can be activated. Autocomplete popup windows for example
+ // cannot be activated. Default is true.
+ bool activatable_;
+
+ // Whether the renderer is made accessible.
+ // TODO(jcampan): http://b/issue?id=1432077 This is a temporary work-around
+ // until that bug is fixed.
+ bool renderer_accessible_;
+
+ DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewWin);
+};
+
+#endif // CHROME_BROWSER_RENDERER_HOST_RENDER_WIDGET_HOST_VIEW_WIN_H_
+
diff --git a/chrome/browser/renderer_host/renderer_security_policy.cc b/chrome/browser/renderer_host/renderer_security_policy.cc
new file mode 100644
index 0000000..ccea740
--- /dev/null
+++ b/chrome/browser/renderer_host/renderer_security_policy.cc
@@ -0,0 +1,285 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/renderer_host/renderer_security_policy.h"
+
+#include "base/logging.h"
+#include "base/string_util.h"
+#ifdef CHROME_PERSONALIZATION
+#include "chrome/personalization/personalization.h"
+#endif
+#include "googleurl/src/gurl.h"
+#include "net/url_request/url_request.h"
+
+// The SecurityState class is used to maintain per-renderer security state
+// information.
+class RendererSecurityPolicy::SecurityState {
+ public:
+ SecurityState() : has_dom_ui_bindings_(false) { }
+
+ // Grant permission to request URLs with the specified scheme.
+ void GrantScheme(const std::string& scheme) {
+ scheme_policy_[scheme] = true;
+ }
+
+ // Revoke permission to request URLs with the specified scheme.
+ void RevokeScheme(const std::string& scheme) {
+ scheme_policy_[scheme] = false;
+ }
+
+ // Grant permission to upload the specified file to the web.
+ void GrantUploadFile(const std::wstring& file) {
+ uploadable_files_.insert(file);
+ }
+
+ void GrantDOMUIBindings() {
+ has_dom_ui_bindings_ = true;
+ }
+
+ // Determine whether permission has been granted to request url.
+ // Schemes that have not been granted default to being denied.
+ bool CanRequestURL(const GURL& url) {
+ SchemeMap::const_iterator judgment(scheme_policy_.find(url.scheme()));
+
+ if (judgment == scheme_policy_.end())
+ return false; // Unmentioned schemes are disallowed.
+
+ return judgment->second;
+ }
+
+ // Determine whether permission has been granted to upload file.
+ // Files that have not been granted default to being denied.
+ bool CanUploadFile(const std::wstring& file) {
+ return uploadable_files_.find(file) != uploadable_files_.end();
+ }
+
+ bool has_dom_ui_bindings() const { return has_dom_ui_bindings_; }
+
+ private:
+ typedef std::map<std::string, bool> SchemeMap;
+ typedef std::set<std::wstring> FileSet;
+
+ // Maps URL schemes to whether permission has been granted or revoked:
+ // |true| means the scheme has been granted.
+ // |false| means the scheme has been revoked.
+ // If a scheme is not present in the map, then it has never been granted
+ // or revoked.
+ SchemeMap scheme_policy_;
+
+ // The set of files the renderer is permited to upload to the web.
+ FileSet uploadable_files_;
+
+ bool has_dom_ui_bindings_;
+
+ DISALLOW_COPY_AND_ASSIGN(SecurityState);
+};
+
+RendererSecurityPolicy::RendererSecurityPolicy() {
+ // We know about these schemes and believe them to be safe.
+ RegisterWebSafeScheme("http");
+ RegisterWebSafeScheme("https");
+ RegisterWebSafeScheme("ftp");
+ RegisterWebSafeScheme("data");
+ RegisterWebSafeScheme("feed");
+
+ // We know about the following psuedo schemes and treat them specially.
+ RegisterPseudoScheme("about");
+ RegisterPseudoScheme("javascript");
+ RegisterPseudoScheme("view-source");
+}
+
+// static
+RendererSecurityPolicy* RendererSecurityPolicy::GetInstance() {
+ return Singleton<RendererSecurityPolicy>::get();
+}
+
+void RendererSecurityPolicy::Add(int renderer_id) {
+ AutoLock lock(lock_);
+ if (security_state_.count(renderer_id) != 0) {
+ NOTREACHED() << "Add renderers at most once.";
+ return;
+ }
+
+ security_state_[renderer_id] = new SecurityState();
+}
+
+void RendererSecurityPolicy::Remove(int renderer_id) {
+ AutoLock lock(lock_);
+ if (security_state_.count(renderer_id) != 1) {
+ NOTREACHED() << "Remove renderers at most once.";
+ return;
+ }
+
+ delete security_state_[renderer_id];
+ security_state_.erase(renderer_id);
+}
+
+void RendererSecurityPolicy::RegisterWebSafeScheme(const std::string& scheme) {
+ AutoLock lock(lock_);
+ DCHECK(web_safe_schemes_.count(scheme) == 0) << "Add schemes at most once.";
+ DCHECK(pseudo_schemes_.count(scheme) == 0) << "Web-safe implies not psuedo.";
+
+ web_safe_schemes_.insert(scheme);
+}
+
+bool RendererSecurityPolicy::IsWebSafeScheme(const std::string& scheme) {
+ AutoLock lock(lock_);
+
+ return (web_safe_schemes_.find(scheme) != web_safe_schemes_.end());
+}
+
+void RendererSecurityPolicy::RegisterPseudoScheme(const std::string& scheme) {
+ AutoLock lock(lock_);
+ DCHECK(pseudo_schemes_.count(scheme) == 0) << "Add schemes at most once.";
+ DCHECK(web_safe_schemes_.count(scheme) == 0) << "Psuedo implies not web-safe.";
+
+ pseudo_schemes_.insert(scheme);
+}
+
+bool RendererSecurityPolicy::IsPseudoScheme(const std::string& scheme) {
+ AutoLock lock(lock_);
+
+ return (pseudo_schemes_.find(scheme) != pseudo_schemes_.end());
+}
+
+void RendererSecurityPolicy::GrantRequestURL(int renderer_id, const GURL& url) {
+
+ if (!url.is_valid())
+ return; // Can't grant the capability to request invalid URLs.
+
+ if (IsWebSafeScheme(url.scheme()))
+ return; // The scheme has already been white-listed for every renderer.
+
+ if (IsPseudoScheme(url.scheme())) {
+ // The view-source scheme is a special case of a pseudo URL that eventually
+ // results in requesting its embedded URL.
+ if (url.SchemeIs("view-source")) {
+ // URLs with the view-source scheme typically look like:
+ // view-source:http://www.google.com/a
+ // In order to request these URLs, the renderer needs to be able to request
+ // the embedded URL.
+ GrantRequestURL(renderer_id, GURL(url.path()));
+ }
+
+ return; // Can't grant the capability to request pseudo schemes.
+ }
+
+ {
+ AutoLock lock(lock_);
+ SecurityStateMap::iterator state = security_state_.find(renderer_id);
+ if (state == security_state_.end())
+ return;
+
+ // If the renderer has been commanded to request a scheme, then we grant
+ // it the capability to request URLs of that scheme.
+ state->second->GrantScheme(url.scheme());
+ }
+}
+
+void RendererSecurityPolicy::GrantUploadFile(int renderer_id,
+ const std::wstring& file) {
+ AutoLock lock(lock_);
+
+ SecurityStateMap::iterator state = security_state_.find(renderer_id);
+ if (state == security_state_.end())
+ return;
+
+ state->second->GrantUploadFile(file);
+}
+
+void RendererSecurityPolicy::GrantInspectElement(int renderer_id) {
+ AutoLock lock(lock_);
+
+ SecurityStateMap::iterator state = security_state_.find(renderer_id);
+ if (state == security_state_.end())
+ return;
+
+ // The inspector is served from a chrome: URL. In order to run the
+ // inspector, the renderer needs to be able to load chrome URLs.
+ state->second->GrantScheme("chrome");
+}
+
+void RendererSecurityPolicy::GrantDOMUIBindings(int renderer_id) {
+ AutoLock lock(lock_);
+
+ SecurityStateMap::iterator state = security_state_.find(renderer_id);
+ if (state == security_state_.end())
+ return;
+
+ state->second->GrantDOMUIBindings();
+
+ // DOM UI bindings need the ability to request chrome URLs.
+ state->second->GrantScheme("chrome");
+
+ // DOM UI pages can contain links to file:// URLs.
+ state->second->GrantScheme("file");
+}
+
+bool RendererSecurityPolicy::CanRequestURL(int renderer_id, const GURL& url) {
+ if (!url.is_valid())
+ return false; // Can't request invalid URLs.
+
+ if (IsWebSafeScheme(url.scheme()))
+ return true; // The scheme has been white-listed for every renderer.
+
+ if (IsPseudoScheme(url.scheme())) {
+ // There are a number of special cases for pseudo schemes.
+
+ if (url.SchemeIs("view-source")) {
+ // A view-source URL is allowed if the renderer is permitted to request
+ // the embedded URL.
+ return CanRequestURL(renderer_id, GURL(url.path()));
+ }
+
+ if (LowerCaseEqualsASCII(url.spec(), "about:blank"))
+ return true; // Every renderer can request <about:blank>.
+
+ // URLs like <about:memory> and <about:crash> shouldn't be requestable by
+ // any renderer. Also, this case covers <javascript:...>, which should be
+ // handled internally by the renderer and not kicked up to the browser.
+ return false;
+ }
+
+#ifdef CHROME_PERSONALIZATION
+ if (url.SchemeIs(kPersonalizationScheme))
+ return true;
+#endif
+
+ if (!URLRequest::IsHandledURL(url))
+ return true; // This URL request is destined for ShellExecute.
+
+ {
+ AutoLock lock(lock_);
+
+ SecurityStateMap::iterator state = security_state_.find(renderer_id);
+ if (state == security_state_.end())
+ return false;
+
+ // Otherwise, we consult the renderer's security state to see if it is
+ // allowed to request the URL.
+ return state->second->CanRequestURL(url);
+ }
+}
+
+bool RendererSecurityPolicy::CanUploadFile(int renderer_id,
+ const std::wstring& file) {
+ AutoLock lock(lock_);
+
+ SecurityStateMap::iterator state = security_state_.find(renderer_id);
+ if (state == security_state_.end())
+ return false;
+
+ return state->second->CanUploadFile(file);
+}
+
+bool RendererSecurityPolicy::HasDOMUIBindings(int renderer_id) {
+ AutoLock lock(lock_);
+
+ SecurityStateMap::iterator state = security_state_.find(renderer_id);
+ if (state == security_state_.end())
+ return false;
+
+ return state->second->has_dom_ui_bindings();
+}
+
diff --git a/chrome/browser/renderer_host/renderer_security_policy.h b/chrome/browser/renderer_host/renderer_security_policy.h
new file mode 100644
index 0000000..646f783
--- /dev/null
+++ b/chrome/browser/renderer_host/renderer_security_policy.h
@@ -0,0 +1,122 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_RENDERER_HOST_RENDERER_SECURITY_POLICY_H_
+#define CHROME_BROWSER_RENDERER_HOST_RENDERER_SECURITY_POLICY_H_
+
+#include <string>
+#include <map>
+#include <set>
+
+#include "base/basictypes.h"
+#include "base/lock.h"
+#include "base/singleton.h"
+
+class GURL;
+
+// The RendererSecurityPolicy class is used to grant and revoke security
+// capabilities for renderers. For example, it restricts whether a renderer
+// is permmitted to loaded file:// URLs based on whether the renderer has ever
+// been commanded to load file:// URLs by the browser.
+//
+// RendererSecurityPolicy is a singleton that may be used on any thread.
+//
+class RendererSecurityPolicy {
+ public:
+ // There is one global RendererSecurityPolicy object for the entire browser
+ // processes. The object returned by this method may be accessed on any
+ // thread.
+ static RendererSecurityPolicy* GetInstance();
+
+ // Web-safe schemes can be requested by any renderer. Once a web-safe scheme
+ // has been registered, any renderer processes can request URLs with that
+ // scheme. There is no mechanism for revoking web-safe schemes.
+ void RegisterWebSafeScheme(const std::string& scheme);
+
+ // Returns true iff |scheme| has been registered as a web-safe scheme.
+ bool IsWebSafeScheme(const std::string& scheme);
+
+ // Pseudo schemes are treated differently than other schemes because they
+ // cannot be requested like normal URLs. There is no mechanism for revoking
+ // pseudo schemes.
+ void RegisterPseudoScheme(const std::string& scheme);
+
+ // Returns true iff |scheme| has been registered as pseudo scheme.
+ bool IsPseudoScheme(const std::string& scheme);
+
+ // Upon creation, render processes should register themselves by calling this
+ // this method exactly once.
+ void Add(int renderer_id);
+
+ // Upon destruction, render processess should unregister themselves by caling
+ // this method exactly once.
+ void Remove(int renderer_id);
+
+ // Whenever the browser processes commands the renderer to request a URL, it
+ // should call this method to grant the renderer process the capability to
+ // request the URL.
+ void GrantRequestURL(int renderer_id, const GURL& url);
+
+ // Whenever the user picks a file from a <input type="file"> element, the
+ // browser should call this function to grant the renderer the capability to
+ // upload the file to the web.
+ void GrantUploadFile(int renderer_id, const std::wstring& file);
+
+ // Whenever the browser processes commands the renderer to run web inspector,
+ // it should call this method to grant the renderer process the capability to
+ // run the inspector.
+ void GrantInspectElement(int renderer_id);
+
+ // Grant this renderer the ability to use DOM UI Bindings.
+ void GrantDOMUIBindings(int renderer_id);
+
+ // Before servicing a renderer's request for a URL, the browser should call
+ // this method to determine whether the renderer has the capability to
+ // request the URL.
+ bool CanRequestURL(int renderer_id, const GURL& url);
+
+ // Before servicing a renderer's request to upload a file to the web, the
+ // browser should call this method to determine whether the renderer has the
+ // capability to upload the requested file.
+ bool CanUploadFile(int renderer_id, const std::wstring& file);
+
+ // Returns true of the specified renderer_id has been granted DOMUIBindings.
+ // The browser should check this property before assuming the renderer is
+ // allowed to use DOMUIBindings.
+ bool HasDOMUIBindings(int renderer_id);
+
+ private:
+ class SecurityState;
+
+ typedef std::set<std::string> SchemeSet;
+ typedef std::map<int, SecurityState*> SecurityStateMap;
+
+ // Obtain an instance of RendererSecurityPolicy via GetInstance().
+ RendererSecurityPolicy();
+ friend struct DefaultSingletonTraits<RendererSecurityPolicy>;
+
+ // You must acquire this lock before reading or writing any members of this
+ // class. You must not block while holding this lock.
+ Lock lock_;
+
+ // These schemes are white-listed for all renderers. This set is protected
+ // by |lock_|.
+ SchemeSet web_safe_schemes_;
+
+ // These schemes do not actually represent retrievable URLs. For example,
+ // the the URLs in the "about" scheme are aliases to other URLs. This set is
+ // protected by |lock_|.
+ SchemeSet pseudo_schemes_;
+
+ // This map holds a SecurityState for each renderer process. The key for the
+ // map is the ID of the RenderProcessHost. The SecurityState objects are
+ // owned by this object and are protected by |lock_|. References to them must
+ // not escape this class.
+ SecurityStateMap security_state_;
+
+ DISALLOW_COPY_AND_ASSIGN(RendererSecurityPolicy);
+};
+
+#endif // CHROME_BROWSER_RENDERER_HOST_RENDERER_SECURITY_POLICY_H_
+
diff --git a/chrome/browser/renderer_host/renderer_security_policy_unittest.cc b/chrome/browser/renderer_host/renderer_security_policy_unittest.cc
new file mode 100644
index 0000000..ae3ac52
--- /dev/null
+++ b/chrome/browser/renderer_host/renderer_security_policy_unittest.cc
@@ -0,0 +1,260 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "chrome/browser/renderer_host/renderer_security_policy.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_test_job.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class RendererSecurityPolicyTest : public testing::Test {
+protected:
+ // testing::Test
+ virtual void SetUp() {
+ // In the real world, "chrome" is a handled scheme.
+ URLRequest::RegisterProtocolFactory("chrome",
+ &URLRequestTestJob::Factory);
+ }
+ virtual void TearDown() {
+ URLRequest::RegisterProtocolFactory("chrome", NULL);
+ }
+};
+
+static int kRendererID = 42;
+
+TEST_F(RendererSecurityPolicyTest, IsWebSafeSchemeTest) {
+ RendererSecurityPolicy* p = RendererSecurityPolicy::GetInstance();
+
+ EXPECT_TRUE(p->IsWebSafeScheme("http"));
+ EXPECT_TRUE(p->IsWebSafeScheme("https"));
+ EXPECT_TRUE(p->IsWebSafeScheme("ftp"));
+ EXPECT_TRUE(p->IsWebSafeScheme("data"));
+ EXPECT_TRUE(p->IsWebSafeScheme("feed"));
+
+ EXPECT_FALSE(p->IsWebSafeScheme("registered-web-safe-scheme"));
+ p->RegisterWebSafeScheme("registered-web-safe-scheme");
+ EXPECT_TRUE(p->IsWebSafeScheme("registered-web-safe-scheme"));
+}
+
+TEST_F(RendererSecurityPolicyTest, IsPseudoSchemeTest) {
+ RendererSecurityPolicy* p = RendererSecurityPolicy::GetInstance();
+
+ EXPECT_TRUE(p->IsPseudoScheme("about"));
+ EXPECT_TRUE(p->IsPseudoScheme("javascript"));
+ EXPECT_TRUE(p->IsPseudoScheme("view-source"));
+
+ EXPECT_FALSE(p->IsPseudoScheme("registered-psuedo-scheme"));
+ p->RegisterPseudoScheme("registered-psuedo-scheme");
+ EXPECT_TRUE(p->IsPseudoScheme("registered-psuedo-scheme"));
+}
+
+TEST_F(RendererSecurityPolicyTest, StandardSchemesTest) {
+ RendererSecurityPolicy* p = RendererSecurityPolicy::GetInstance();
+
+ p->Add(kRendererID);
+
+ // Safe
+ EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("http://www.google.com/")));
+ EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("https://www.paypal.com/")));
+ EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("ftp://ftp.gnu.org/")));
+ EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("data:text/html,<b>Hi</b>")));
+ EXPECT_TRUE(p->CanRequestURL(kRendererID,
+ GURL("view-source:http://www.google.com/")));
+
+ // Dangerous
+ EXPECT_FALSE(p->CanRequestURL(kRendererID,
+ GURL("file:///etc/passwd")));
+ EXPECT_FALSE(p->CanRequestURL(kRendererID,
+ GURL("view-cache:http://www.google.com/")));
+ EXPECT_FALSE(p->CanRequestURL(kRendererID,
+ GURL("chrome://foo/bar")));
+
+ p->Remove(kRendererID);
+}
+
+TEST_F(RendererSecurityPolicyTest, AboutTest) {
+ RendererSecurityPolicy* p = RendererSecurityPolicy::GetInstance();
+
+ p->Add(kRendererID);
+
+ EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("about:blank")));
+ EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("about:BlAnK")));
+ EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("aBouT:BlAnK")));
+ EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("aBouT:blank")));
+
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("about:memory")));
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("about:crash")));
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("about:cache")));
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("about:hang")));
+
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("aBoUt:memory")));
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("about:CrASh")));
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("abOuT:cAChe")));
+
+ p->GrantRequestURL(kRendererID, GURL("about:memory"));
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("about:memory")));
+
+ p->GrantRequestURL(kRendererID, GURL("about:crash"));
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("about:crash")));
+
+ p->GrantRequestURL(kRendererID, GURL("about:cache"));
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("about:cache")));
+
+ p->GrantRequestURL(kRendererID, GURL("about:hang"));
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("about:hang")));
+
+ p->Remove(kRendererID);
+}
+
+TEST_F(RendererSecurityPolicyTest, JavaScriptTest) {
+ RendererSecurityPolicy* p = RendererSecurityPolicy::GetInstance();
+
+ p->Add(kRendererID);
+
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("javascript:alert('xss')")));
+ p->GrantRequestURL(kRendererID, GURL("javascript:alert('xss')"));
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("javascript:alert('xss')")));
+
+ p->Remove(kRendererID);
+}
+
+TEST_F(RendererSecurityPolicyTest, RegisterWebSafeSchemeTest) {
+ RendererSecurityPolicy* p = RendererSecurityPolicy::GetInstance();
+
+ p->Add(kRendererID);
+
+ // Currently, "asdf" is destined for ShellExecute, so it is allowed.
+ EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("asdf:rockers")));
+
+ // Once we register a ProtocolFactory for "asdf", we default to deny.
+ URLRequest::RegisterProtocolFactory("asdf", &URLRequestTestJob::Factory);
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("asdf:rockers")));
+
+ // We can allow new schemes by adding them to the whitelist.
+ p->RegisterWebSafeScheme("asdf");
+ EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("asdf:rockers")));
+
+ // Cleanup.
+ URLRequest::RegisterProtocolFactory("asdf", NULL);
+ EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("asdf:rockers")));
+
+ p->Remove(kRendererID);
+}
+
+TEST_F(RendererSecurityPolicyTest, CanServiceCommandsTest) {
+ RendererSecurityPolicy* p = RendererSecurityPolicy::GetInstance();
+
+ p->Add(kRendererID);
+
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("file:///etc/passwd")));
+ p->GrantRequestURL(kRendererID, GURL("file:///etc/passwd"));
+ EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("file:///etc/passwd")));
+
+ // We should forget our state if we repeat a renderer id.
+ p->Remove(kRendererID);
+ p->Add(kRendererID);
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("file:///etc/passwd")));
+ p->Remove(kRendererID);
+}
+
+TEST_F(RendererSecurityPolicyTest, ViewSource) {
+ RendererSecurityPolicy* p = RendererSecurityPolicy::GetInstance();
+
+ p->Add(kRendererID);
+
+ // View source is determined by the embedded scheme.
+ EXPECT_TRUE(p->CanRequestURL(kRendererID,
+ GURL("view-source:http://www.google.com/")));
+ EXPECT_FALSE(p->CanRequestURL(kRendererID,
+ GURL("view-source:file:///etc/passwd")));
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("file:///etc/passwd")));
+
+ p->GrantRequestURL(kRendererID, GURL("view-source:file:///etc/passwd"));
+ // View source needs to be able to request the embedded scheme.
+ EXPECT_TRUE(p->CanRequestURL(kRendererID,
+ GURL("view-source:file:///etc/passwd")));
+ EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("file:///etc/passwd")));
+
+ p->Remove(kRendererID);
+}
+
+TEST_F(RendererSecurityPolicyTest, CanUploadFiles) {
+ RendererSecurityPolicy* p = RendererSecurityPolicy::GetInstance();
+
+ p->Add(kRendererID);
+
+ EXPECT_FALSE(p->CanUploadFile(kRendererID, L"/etc/passwd"));
+ p->GrantUploadFile(kRendererID, L"/etc/passwd");
+ EXPECT_TRUE(p->CanUploadFile(kRendererID, L"/etc/passwd"));
+ EXPECT_FALSE(p->CanUploadFile(kRendererID, L"/etc/shadow"));
+
+ p->Remove(kRendererID);
+ p->Add(kRendererID);
+
+ EXPECT_FALSE(p->CanUploadFile(kRendererID, L"/etc/passwd"));
+ EXPECT_FALSE(p->CanUploadFile(kRendererID, L"/etc/shadow"));
+
+ p->Remove(kRendererID);
+}
+
+TEST_F(RendererSecurityPolicyTest, CanServiceInspectElement) {
+ RendererSecurityPolicy* p = RendererSecurityPolicy::GetInstance();
+
+ GURL url("chrome://inspector/inspector.html");
+
+ p->Add(kRendererID);
+
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, url));
+ p->GrantInspectElement(kRendererID);
+ EXPECT_TRUE(p->CanRequestURL(kRendererID, url));
+
+ p->Remove(kRendererID);
+}
+
+TEST_F(RendererSecurityPolicyTest, CanServiceDOMUIBindings) {
+ RendererSecurityPolicy* p = RendererSecurityPolicy::GetInstance();
+
+ GURL url("chrome://thumb/http://www.google.com/");
+
+ p->Add(kRendererID);
+
+ EXPECT_FALSE(p->HasDOMUIBindings(kRendererID));
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, url));
+ p->GrantDOMUIBindings(kRendererID);
+ EXPECT_TRUE(p->HasDOMUIBindings(kRendererID));
+ EXPECT_TRUE(p->CanRequestURL(kRendererID, url));
+
+ p->Remove(kRendererID);
+}
+
+TEST_F(RendererSecurityPolicyTest, RemoveRace) {
+ RendererSecurityPolicy* p = RendererSecurityPolicy::GetInstance();
+
+ GURL url("file:///etc/passwd");
+ std::wstring file(L"/etc/passwd");
+
+ p->Add(kRendererID);
+
+ p->GrantRequestURL(kRendererID, url);
+ p->GrantUploadFile(kRendererID, file);
+ p->GrantDOMUIBindings(kRendererID);
+
+ EXPECT_TRUE(p->CanRequestURL(kRendererID, url));
+ EXPECT_TRUE(p->CanUploadFile(kRendererID, file));
+ EXPECT_TRUE(p->HasDOMUIBindings(kRendererID));
+
+ p->Remove(kRendererID);
+
+ // Renderers are added and removed on the UI thread, but the policy can be
+ // queried on the IO thread. The RendererSecurityPolicy needs to be prepared
+ // to answer policy questions about renderers who no longer exist.
+
+ // In this case, we default to secure behavior.
+ EXPECT_FALSE(p->CanRequestURL(kRendererID, url));
+ EXPECT_FALSE(p->CanUploadFile(kRendererID, file));
+ EXPECT_FALSE(p->HasDOMUIBindings(kRendererID));
+}
+
diff --git a/chrome/browser/renderer_host/resource_dispatcher_host.cc b/chrome/browser/renderer_host/resource_dispatcher_host.cc
index 7c74420..261d1c1 100644
--- a/chrome/browser/renderer_host/resource_dispatcher_host.cc
+++ b/chrome/browser/renderer_host/resource_dispatcher_host.cc
@@ -20,16 +20,16 @@
#include "chrome/browser/external_protocol_handler.h"
#include "chrome/browser/login_prompt.h"
#include "chrome/browser/plugin_service.h"
-#include "chrome/browser/render_view_host.h"
-#include "chrome/browser/render_view_host_delegate.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/renderer_host/render_view_host_delegate.h"
#include "chrome/browser/renderer_host/async_resource_handler.h"
#include "chrome/browser/renderer_host/buffered_resource_handler.h"
#include "chrome/browser/renderer_host/cross_site_resource_handler.h"
#include "chrome/browser/renderer_host/download_resource_handler.h"
+#include "chrome/browser/renderer_host/renderer_security_policy.h"
#include "chrome/browser/renderer_host/safe_browsing_resource_handler.h"
#include "chrome/browser/renderer_host/save_file_resource_handler.h"
#include "chrome/browser/renderer_host/sync_resource_handler.h"
-#include "chrome/browser/renderer_security_policy.h"
#include "chrome/browser/resource_request_details.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
#include "chrome/browser/tab_contents/tab_util.h"
diff --git a/chrome/browser/renderer_host/test_render_view_host.cc b/chrome/browser/renderer_host/test_render_view_host.cc
index 7c47b53..1c77bb8 100644
--- a/chrome/browser/renderer_host/test_render_view_host.cc
+++ b/chrome/browser/renderer_host/test_render_view_host.cc
@@ -73,8 +73,10 @@ void RenderViewHostTestHarness::SetUp() {
}
void RenderViewHostTestHarness::TearDown() {
- contents_->CloseContents();
- contents_ = NULL;
+ if (contents_) {
+ contents_->CloseContents();
+ contents_ = NULL;
+ }
controller_ = NULL;
// Make sure that we flush any messages related to WebContents destruction
diff --git a/chrome/browser/renderer_host/test_render_view_host.h b/chrome/browser/renderer_host/test_render_view_host.h
index ba7c7ea..be7acfe 100644
--- a/chrome/browser/renderer_host/test_render_view_host.h
+++ b/chrome/browser/renderer_host/test_render_view_host.h
@@ -9,9 +9,9 @@
#include "base/message_loop.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/test_web_contents.h"
-#include "chrome/browser/render_view_host.h"
#include "chrome/browser/renderer_host/mock_render_process_host.h"
-#include "chrome/browser/render_widget_host_view.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/test/testing_profile.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -183,6 +183,12 @@ class RenderViewHostTestHarness : public testing::Test {
return profile_.get();
}
+ // Marks the contents as already cleaned up. If a test calls CloseContents,
+ // then our cleanup code shouldn't run. This function makes sure that happens.
+ void ContentsCleanedUp() {
+ contents_ = NULL;
+ }
+
protected:
// testing::Test
virtual void SetUp();