Commit 7d47247a authored by jam@chromium.org's avatar jam@chromium.org

Get rid of RenderViewHostDelegate::BrowserIntegration since it was...

Get rid of RenderViewHostDelegate::BrowserIntegration since it was unnecessary.  RenderViewHost used to dispatch messages only to call that interface, and TabContents would do the work.  Instead have TabContents dispatch the messages directly.
Review URL: http://codereview.chromium.org/6336012

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@72250 0039d316-1c4b-4281-b951-d872f2087c98
parent 4f627234
...@@ -761,7 +761,6 @@ bool RenderViewHost::OnMessageReceived(const IPC::Message& msg) { ...@@ -761,7 +761,6 @@ bool RenderViewHost::OnMessageReceived(const IPC::Message& msg) {
OnMsgDocumentAvailableInMainFrame) OnMsgDocumentAvailableInMainFrame)
IPC_MESSAGE_HANDLER(ViewHostMsg_DocumentOnLoadCompletedInMainFrame, IPC_MESSAGE_HANDLER(ViewHostMsg_DocumentOnLoadCompletedInMainFrame,
OnMsgDocumentOnLoadCompletedInMainFrame) OnMsgDocumentOnLoadCompletedInMainFrame)
IPC_MESSAGE_HANDLER(ViewHostMsg_Find_Reply, OnMsgFindReply)
IPC_MESSAGE_HANDLER(ViewMsg_ExecuteCodeFinished, IPC_MESSAGE_HANDLER(ViewMsg_ExecuteCodeFinished,
OnExecuteCodeFinished) OnExecuteCodeFinished)
IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateFavIconURL, OnMsgUpdateFavIconURL) IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateFavIconURL, OnMsgUpdateFavIconURL)
...@@ -775,7 +774,6 @@ bool RenderViewHost::OnMessageReceived(const IPC::Message& msg) { ...@@ -775,7 +774,6 @@ bool RenderViewHost::OnMessageReceived(const IPC::Message& msg) {
IPC_MESSAGE_HANDLER(ViewHostMsg_DOMUISend, OnMsgDOMUISend) IPC_MESSAGE_HANDLER(ViewHostMsg_DOMUISend, OnMsgDOMUISend)
IPC_MESSAGE_HANDLER(ViewHostMsg_ForwardMessageToExternalHost, IPC_MESSAGE_HANDLER(ViewHostMsg_ForwardMessageToExternalHost,
OnMsgForwardMessageToExternalHost) OnMsgForwardMessageToExternalHost)
IPC_MESSAGE_HANDLER(ViewHostMsg_GoToEntryAtOffset, OnMsgGoToEntryAtOffset)
IPC_MESSAGE_HANDLER(ViewHostMsg_SetTooltipText, OnMsgSetTooltipText) IPC_MESSAGE_HANDLER(ViewHostMsg_SetTooltipText, OnMsgSetTooltipText)
IPC_MESSAGE_HANDLER(ViewHostMsg_RunFileChooser, OnMsgRunFileChooser) IPC_MESSAGE_HANDLER(ViewHostMsg_RunFileChooser, OnMsgRunFileChooser)
IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_RunJavaScriptMessage, IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_RunJavaScriptMessage,
...@@ -806,18 +804,10 @@ bool RenderViewHost::OnMessageReceived(const IPC::Message& msg) { ...@@ -806,18 +804,10 @@ bool RenderViewHost::OnMessageReceived(const IPC::Message& msg) {
OnRequestUndockDevToolsWindow) OnRequestUndockDevToolsWindow)
IPC_MESSAGE_HANDLER(ViewHostMsg_DevToolsRuntimePropertyChanged, IPC_MESSAGE_HANDLER(ViewHostMsg_DevToolsRuntimePropertyChanged,
OnDevToolsRuntimePropertyChanged) OnDevToolsRuntimePropertyChanged)
IPC_MESSAGE_HANDLER(ViewHostMsg_MissingPluginStatus, OnMissingPluginStatus)
IPC_MESSAGE_HANDLER(ViewHostMsg_CrashedPlugin, OnCrashedPlugin)
IPC_MESSAGE_HANDLER(ViewHostMsg_BlockedOutdatedPlugin,
OnBlockedOutdatedPlugin)
IPC_MESSAGE_HANDLER(ViewHostMsg_SendCurrentPageAllSavableResourceLinks, IPC_MESSAGE_HANDLER(ViewHostMsg_SendCurrentPageAllSavableResourceLinks,
OnReceivedSavableResourceLinksForCurrentPage) OnReceivedSavableResourceLinksForCurrentPage)
IPC_MESSAGE_HANDLER(ViewHostMsg_SendSerializedHtmlData, IPC_MESSAGE_HANDLER(ViewHostMsg_SendSerializedHtmlData,
OnReceivedSerializedHtmlData) OnReceivedSerializedHtmlData)
IPC_MESSAGE_HANDLER(ViewHostMsg_DidGetApplicationInfo,
OnDidGetApplicationInfo)
IPC_MESSAGE_HANDLER(ViewHostMsg_InstallApplication,
OnInstallApplication)
IPC_MESSAGE_FORWARD(ViewHostMsg_JSOutOfMemory, delegate_, IPC_MESSAGE_FORWARD(ViewHostMsg_JSOutOfMemory, delegate_,
RenderViewHostDelegate::OnJSOutOfMemory) RenderViewHostDelegate::OnJSOutOfMemory)
IPC_MESSAGE_HANDLER(ViewHostMsg_ShouldClose_ACK, OnMsgShouldCloseACK) IPC_MESSAGE_HANDLER(ViewHostMsg_ShouldClose_ACK, OnMsgShouldCloseACK)
...@@ -834,16 +824,11 @@ bool RenderViewHost::OnMessageReceived(const IPC::Message& msg) { ...@@ -834,16 +824,11 @@ bool RenderViewHost::OnMessageReceived(const IPC::Message& msg) {
IPC_MESSAGE_HANDLER(ViewHostMsg_AccessibilityNotifications, IPC_MESSAGE_HANDLER(ViewHostMsg_AccessibilityNotifications,
OnAccessibilityNotifications) OnAccessibilityNotifications)
IPC_MESSAGE_HANDLER(ViewHostMsg_OnCSSInserted, OnCSSInserted) IPC_MESSAGE_HANDLER(ViewHostMsg_OnCSSInserted, OnCSSInserted)
IPC_MESSAGE_HANDLER(ViewHostMsg_PageContents, OnPageContents)
IPC_MESSAGE_HANDLER(ViewHostMsg_PageTranslated, OnPageTranslated)
IPC_MESSAGE_HANDLER(ViewHostMsg_ContentBlocked, OnContentBlocked) IPC_MESSAGE_HANDLER(ViewHostMsg_ContentBlocked, OnContentBlocked)
IPC_MESSAGE_HANDLER(ViewHostMsg_AppCacheAccessed, OnAppCacheAccessed) IPC_MESSAGE_HANDLER(ViewHostMsg_AppCacheAccessed, OnAppCacheAccessed)
IPC_MESSAGE_HANDLER(ViewHostMsg_WebDatabaseAccessed, OnWebDatabaseAccessed) IPC_MESSAGE_HANDLER(ViewHostMsg_WebDatabaseAccessed, OnWebDatabaseAccessed)
IPC_MESSAGE_HANDLER(ViewHostMsg_FocusedNodeChanged, OnMsgFocusedNodeChanged) IPC_MESSAGE_HANDLER(ViewHostMsg_FocusedNodeChanged, OnMsgFocusedNodeChanged)
IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateZoomLimits, OnUpdateZoomLimits) IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateZoomLimits, OnUpdateZoomLimits)
IPC_MESSAGE_HANDLER(ViewHostMsg_SetSuggestions, OnSetSuggestions)
IPC_MESSAGE_HANDLER(ViewHostMsg_InstantSupportDetermined,
OnInstantSupportDetermined)
IPC_MESSAGE_HANDLER(ViewHostMsg_DetectedPhishingSite, IPC_MESSAGE_HANDLER(ViewHostMsg_DetectedPhishingSite,
OnDetectedPhishingSite) OnDetectedPhishingSite)
IPC_MESSAGE_HANDLER(ViewHostMsg_ScriptEvalResponse, OnScriptEvalResponse) IPC_MESSAGE_HANDLER(ViewHostMsg_ScriptEvalResponse, OnScriptEvalResponse)
...@@ -1110,28 +1095,6 @@ void RenderViewHost::OnMsgDocumentOnLoadCompletedInMainFrame(int32 page_id) { ...@@ -1110,28 +1095,6 @@ void RenderViewHost::OnMsgDocumentOnLoadCompletedInMainFrame(int32 page_id) {
delegate_->DocumentOnLoadCompletedInMainFrame(this, page_id); delegate_->DocumentOnLoadCompletedInMainFrame(this, page_id);
} }
void RenderViewHost::OnMsgFindReply(int request_id,
int number_of_matches,
const gfx::Rect& selection_rect,
int active_match_ordinal,
bool final_update) {
RenderViewHostDelegate::BrowserIntegration* integration_delegate =
delegate_->GetBrowserIntegrationDelegate();
if (integration_delegate) {
integration_delegate->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::OnExecuteCodeFinished(int request_id, bool success) { void RenderViewHost::OnExecuteCodeFinished(int request_id, bool success) {
std::pair<int, bool> result_details(request_id, success); std::pair<int, bool> result_details(request_id, success);
NotificationService::current()->Notify( NotificationService::current()->Notify(
...@@ -1257,13 +1220,6 @@ void RenderViewHost::AllowScriptToClose(bool script_can_close) { ...@@ -1257,13 +1220,6 @@ void RenderViewHost::AllowScriptToClose(bool script_can_close) {
Send(new ViewMsg_AllowScriptToClose(routing_id(), script_can_close)); Send(new ViewMsg_AllowScriptToClose(routing_id(), script_can_close));
} }
void RenderViewHost::OnMsgGoToEntryAtOffset(int offset) {
RenderViewHostDelegate::BrowserIntegration* integration_delegate =
delegate_->GetBrowserIntegrationDelegate();
if (integration_delegate)
integration_delegate->GoToEntryAtOffset(offset);
}
void RenderViewHost::OnMsgSetTooltipText( void RenderViewHost::OnMsgSetTooltipText(
const std::wstring& tooltip_text, const std::wstring& tooltip_text,
WebTextDirection text_direction_hint) { WebTextDirection text_direction_hint) {
...@@ -1453,32 +1409,7 @@ void RenderViewHost::UnhandledKeyboardEvent( ...@@ -1453,32 +1409,7 @@ void RenderViewHost::UnhandledKeyboardEvent(
} }
void RenderViewHost::OnUserGesture() { void RenderViewHost::OnUserGesture() {
RenderViewHostDelegate::BrowserIntegration* integration_delegate = delegate_->OnUserGesture();
delegate_->GetBrowserIntegrationDelegate();
if (integration_delegate)
integration_delegate->OnUserGesture();
}
void RenderViewHost::OnMissingPluginStatus(int status) {
RenderViewHostDelegate::BrowserIntegration* integration_delegate =
delegate_->GetBrowserIntegrationDelegate();
if (integration_delegate)
integration_delegate->OnMissingPluginStatus(status);
}
void RenderViewHost::OnCrashedPlugin(const FilePath& plugin_path) {
RenderViewHostDelegate::BrowserIntegration* integration_delegate =
delegate_->GetBrowserIntegrationDelegate();
if (integration_delegate)
integration_delegate->OnCrashedPlugin(plugin_path);
}
void RenderViewHost::OnBlockedOutdatedPlugin(const string16& name,
const GURL& update_url) {
RenderViewHostDelegate::BrowserIntegration* integration_delegate =
delegate_->GetBrowserIntegrationDelegate();
if (integration_delegate)
integration_delegate->OnBlockedOutdatedPlugin(name, update_url);
} }
void RenderViewHost::GetAllSavableResourceLinksForCurrentPage( void RenderViewHost::GetAllSavableResourceLinksForCurrentPage(
...@@ -1498,22 +1429,6 @@ void RenderViewHost::OnReceivedSavableResourceLinksForCurrentPage( ...@@ -1498,22 +1429,6 @@ void RenderViewHost::OnReceivedSavableResourceLinksForCurrentPage(
} }
} }
void RenderViewHost::OnDidGetApplicationInfo(
int32 page_id, const WebApplicationInfo& info) {
RenderViewHostDelegate::BrowserIntegration* integration_delegate =
delegate_->GetBrowserIntegrationDelegate();
if (integration_delegate)
integration_delegate->OnDidGetApplicationInfo(page_id, info);
}
void RenderViewHost::OnInstallApplication(
const WebApplicationInfo& info) {
RenderViewHostDelegate::BrowserIntegration* integration_delegate =
delegate_->GetBrowserIntegrationDelegate();
if (integration_delegate)
integration_delegate->OnInstallApplication(info);
}
void RenderViewHost::GetSerializedHtmlDataForCurrentPageWithLocalLinks( void RenderViewHost::GetSerializedHtmlDataForCurrentPageWithLocalLinks(
const std::vector<GURL>& links, const std::vector<GURL>& links,
const std::vector<FilePath>& local_paths, const std::vector<FilePath>& local_paths,
...@@ -1829,31 +1744,6 @@ void RenderViewHost::OnCSSInserted() { ...@@ -1829,31 +1744,6 @@ void RenderViewHost::OnCSSInserted() {
delegate_->DidInsertCSS(); delegate_->DidInsertCSS();
} }
void RenderViewHost::OnPageContents(const GURL& url,
int32 page_id,
const string16& contents,
const std::string& language,
bool page_translatable) {
RenderViewHostDelegate::BrowserIntegration* integration_delegate =
delegate_->GetBrowserIntegrationDelegate();
if (!integration_delegate)
return;
integration_delegate->OnPageContents(url, process()->id(), page_id, contents,
language, page_translatable);
}
void RenderViewHost::OnPageTranslated(int32 page_id,
const std::string& original_lang,
const std::string& translated_lang,
TranslateErrors::Type error_type) {
RenderViewHostDelegate::BrowserIntegration* integration_delegate =
delegate_->GetBrowserIntegrationDelegate();
if (!integration_delegate)
return;
integration_delegate->OnPageTranslated(page_id, original_lang,
translated_lang, error_type);
}
void RenderViewHost::OnContentBlocked(ContentSettingsType type, void RenderViewHost::OnContentBlocked(ContentSettingsType type,
const std::string& resource_identifier) { const std::string& resource_identifier) {
RenderViewHostDelegate::ContentSettings* content_settings_delegate = RenderViewHostDelegate::ContentSettings* content_settings_delegate =
...@@ -1889,24 +1779,6 @@ void RenderViewHost::OnUpdateZoomLimits(int minimum_percent, ...@@ -1889,24 +1779,6 @@ void RenderViewHost::OnUpdateZoomLimits(int minimum_percent,
delegate_->UpdateZoomLimits(minimum_percent, maximum_percent, remember); delegate_->UpdateZoomLimits(minimum_percent, maximum_percent, remember);
} }
void RenderViewHost::OnSetSuggestions(
int32 page_id,
const std::vector<std::string>& suggestions) {
RenderViewHostDelegate::BrowserIntegration* integration_delegate =
delegate_->GetBrowserIntegrationDelegate();
if (!integration_delegate)
return;
integration_delegate->OnSetSuggestions(page_id, suggestions);
}
void RenderViewHost::OnInstantSupportDetermined(int32 page_id, bool result) {
RenderViewHostDelegate::BrowserIntegration* integration_delegate =
delegate_->GetBrowserIntegrationDelegate();
if (!integration_delegate)
return;
integration_delegate->OnInstantSupportDetermined(page_id, result);
}
void RenderViewHost::OnDetectedPhishingSite(const GURL& phishing_url, void RenderViewHost::OnDetectedPhishingSite(const GURL& phishing_url,
double phishing_score) { double phishing_score) {
// TODO(noelutz): send an HTTP request to the client-side detection frontends // TODO(noelutz): send an HTTP request to the client-side detection frontends
......
...@@ -569,11 +569,6 @@ class RenderViewHost : public RenderWidgetHost { ...@@ -569,11 +569,6 @@ class RenderViewHost : public RenderWidgetHost {
void OnMsgDidChangeLoadProgress(double load_progress); void OnMsgDidChangeLoadProgress(double load_progress);
void OnMsgDocumentAvailableInMainFrame(); void OnMsgDocumentAvailableInMainFrame();
void OnMsgDocumentOnLoadCompletedInMainFrame(int32 page_id); void OnMsgDocumentOnLoadCompletedInMainFrame(int32 page_id);
void OnMsgFindReply(int request_id,
int number_of_matches,
const gfx::Rect& selection_rect,
int active_match_ordinal,
bool final_update);
void OnExecuteCodeFinished(int request_id, bool success); void OnExecuteCodeFinished(int request_id, bool success);
void OnMsgUpdateFavIconURL(int32 page_id, const GURL& icon_url); void OnMsgUpdateFavIconURL(int32 page_id, const GURL& icon_url);
void OnMsgDidDownloadFavIcon(int id, void OnMsgDidDownloadFavIcon(int id,
...@@ -592,7 +587,6 @@ class RenderViewHost : public RenderWidgetHost { ...@@ -592,7 +587,6 @@ class RenderViewHost : public RenderWidgetHost {
void OnMsgForwardMessageToExternalHost(const std::string& message, void OnMsgForwardMessageToExternalHost(const std::string& message,
const std::string& origin, const std::string& origin,
const std::string& target); const std::string& target);
void OnMsgGoToEntryAtOffset(int offset);
void OnMsgSetTooltipText(const std::wstring& tooltip_text, void OnMsgSetTooltipText(const std::wstring& tooltip_text,
WebKit::WebTextDirection text_direction_hint); WebKit::WebTextDirection text_direction_hint);
void OnMsgSelectionChanged(const std::string& text); void OnMsgSelectionChanged(const std::string& text);
...@@ -633,21 +627,14 @@ class RenderViewHost : public RenderWidgetHost { ...@@ -633,21 +627,14 @@ class RenderViewHost : public RenderWidgetHost {
void OnRequestUndockDevToolsWindow(); void OnRequestUndockDevToolsWindow();
void OnDevToolsRuntimePropertyChanged(const std::string& name, void OnDevToolsRuntimePropertyChanged(const std::string& name,
const std::string& value); const std::string& value);
void OnMissingPluginStatus(int status);
void OnCrashedPlugin(const FilePath& plugin_path);
void OnBlockedOutdatedPlugin(const string16& name, const GURL& update_url);
void OnReceivedSavableResourceLinksForCurrentPage( void OnReceivedSavableResourceLinksForCurrentPage(
const std::vector<GURL>& resources_list, const std::vector<GURL>& resources_list,
const std::vector<GURL>& referrers_list, const std::vector<GURL>& referrers_list,
const std::vector<GURL>& frames_list); const std::vector<GURL>& frames_list);
void OnReceivedSerializedHtmlData(const GURL& frame_url, void OnReceivedSerializedHtmlData(const GURL& frame_url,
const std::string& data, const std::string& data,
int32 status); int32 status);
void OnDidGetApplicationInfo(int32 page_id, const WebApplicationInfo& info);
void OnInstallApplication(const WebApplicationInfo& info);
void OnMsgShouldCloseACK(bool proceed); void OnMsgShouldCloseACK(bool proceed);
void OnShowDesktopNotification( void OnShowDesktopNotification(
const ViewHostMsg_ShowNotification_Params& params); const ViewHostMsg_ShowNotification_Params& params);
...@@ -659,15 +646,6 @@ class RenderViewHost : public RenderWidgetHost { ...@@ -659,15 +646,6 @@ class RenderViewHost : public RenderWidgetHost {
void OnAccessibilityNotifications( void OnAccessibilityNotifications(
const std::vector<ViewHostMsg_AccessibilityNotification_Params>& params); const std::vector<ViewHostMsg_AccessibilityNotification_Params>& params);
void OnCSSInserted(); void OnCSSInserted();
void OnPageContents(const GURL& url,
int32 page_id,
const string16& contents,
const std::string& language,
bool page_translatable);
void OnPageTranslated(int32 page_id,
const std::string& original_lang,
const std::string& translated_lang,
TranslateErrors::Type error_type);
void OnContentBlocked(ContentSettingsType type, void OnContentBlocked(ContentSettingsType type,
const std::string& resource_identifier); const std::string& resource_identifier);
void OnAppCacheAccessed(const GURL& manifest_url, bool blocked_by_policy); void OnAppCacheAccessed(const GURL& manifest_url, bool blocked_by_policy);
...@@ -679,9 +657,6 @@ class RenderViewHost : public RenderWidgetHost { ...@@ -679,9 +657,6 @@ class RenderViewHost : public RenderWidgetHost {
void OnUpdateZoomLimits(int minimum_percent, void OnUpdateZoomLimits(int minimum_percent,
int maximum_percent, int maximum_percent,
bool remember); bool remember);
void OnSetSuggestions(int32 page_id,
const std::vector<std::string>& suggestions);
void OnInstantSupportDetermined(int32 page_id, bool result);
void OnDetectedPhishingSite(const GURL& phishing_url, double phishing_score); void OnDetectedPhishingSite(const GURL& phishing_url, double phishing_score);
void OnScriptEvalResponse(int id, const ListValue& result); void OnScriptEvalResponse(int id, const ListValue& result);
void OnPagesReadyForPreview( void OnPagesReadyForPreview(
......
...@@ -25,12 +25,6 @@ RenderViewHostDelegate::GetRendererManagementDelegate() { ...@@ -25,12 +25,6 @@ RenderViewHostDelegate::GetRendererManagementDelegate() {
return NULL; return NULL;
} }
RenderViewHostDelegate::BrowserIntegration*
RenderViewHostDelegate::GetBrowserIntegrationDelegate() {
return NULL;
}
RenderViewHostDelegate::ContentSettings* RenderViewHostDelegate::ContentSettings*
RenderViewHostDelegate::GetContentSettingsDelegate() { RenderViewHostDelegate::GetContentSettingsDelegate() {
return NULL; return NULL;
......
...@@ -248,80 +248,6 @@ class RenderViewHostDelegate : public IPC::Channel::Listener { ...@@ -248,80 +248,6 @@ class RenderViewHostDelegate : public IPC::Channel::Listener {
virtual ~RendererManagement() {} virtual ~RendererManagement() {}
}; };
// BrowserIntegration --------------------------------------------------------
// Functions that integrate with other browser services.
class BrowserIntegration {
public:
// Notification the user has made a gesture while focus was on the
// page. This is used to avoid uninitiated user downloads (aka carpet
// bombing), see DownloadRequestLimiter for details.
virtual void OnUserGesture() = 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;
// 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) = 0;
// Notification when default plugin updates status of the missing plugin.
virtual void OnMissingPluginStatus(int status) = 0;
// Notification from the renderer that a plugin instance has crashed.
//
// BrowserIntegration isn't necessarily the best place for this, if you
// need to implement this function somewhere that doesn't need any other
// BrowserIntegration callbacks, feel free to move it elsewhere.
virtual void OnCrashedPlugin(const FilePath& plugin_path) = 0;
// Notification that a worker process has crashed.
virtual void OnCrashedWorker() = 0;
virtual void OnBlockedOutdatedPlugin(const string16& name,
const GURL& update_url) = 0;
// Notification that a user's request to install an application has
// completed.
virtual void OnDidGetApplicationInfo(
int32 page_id,
const WebApplicationInfo& app_info) = 0;
// Notification when an application programmatically requests installation.
virtual void OnInstallApplication(
const WebApplicationInfo& app_info) = 0;
// Notification that the contents of the page has been loaded.
virtual void OnPageContents(const GURL& url,
int renderer_process_id,
int32 page_id,
const string16& contents,
const std::string& language,
bool page_translatable) = 0;
// Notification that the page has been translated.
virtual void OnPageTranslated(int32 page_id,
const std::string& original_lang,
const std::string& translated_lang,
TranslateErrors::Type error_type) = 0;
// Notification that the page has a suggest result.
virtual void OnSetSuggestions(
int32 page_id,
const std::vector<std::string>& result) = 0;
// Notification of whether the page supports instant-style interaction.
virtual void OnInstantSupportDetermined(int32 page_id, bool result) = 0;
protected:
virtual ~BrowserIntegration() {}
};
// ContentSettings------------------------------------------------------------ // ContentSettings------------------------------------------------------------
// Interface for content settings related events. // Interface for content settings related events.
...@@ -539,7 +465,6 @@ class RenderViewHostDelegate : public IPC::Channel::Listener { ...@@ -539,7 +465,6 @@ class RenderViewHostDelegate : public IPC::Channel::Listener {
// there is no corresponding delegate. // there is no corresponding delegate.
virtual View* GetViewDelegate(); virtual View* GetViewDelegate();
virtual RendererManagement* GetRendererManagementDelegate(); virtual RendererManagement* GetRendererManagementDelegate();
virtual BrowserIntegration* GetBrowserIntegrationDelegate();
virtual ContentSettings* GetContentSettingsDelegate(); virtual ContentSettings* GetContentSettingsDelegate();
virtual Save* GetSaveDelegate(); virtual Save* GetSaveDelegate();
virtual Printing* GetPrintingDelegate(); virtual Printing* GetPrintingDelegate();
...@@ -708,6 +633,11 @@ class RenderViewHostDelegate : public IPC::Channel::Listener { ...@@ -708,6 +633,11 @@ class RenderViewHostDelegate : public IPC::Channel::Listener {
// associated with the owning render view host. // associated with the owning render view host.
virtual WebPreferences GetWebkitPrefs(); virtual WebPreferences GetWebkitPrefs();
// Notification the user has made a gesture while focus was on the
// page. This is used to avoid uninitiated user downloads (aka carpet
// bombing), see DownloadRequestLimiter for details.
virtual void OnUserGesture() {}
// Notification from the renderer host that blocked UI event occurred. // Notification from the renderer host that blocked UI event occurred.
// This happens when there are tab-modal dialogs. In this case, the // This happens when there are tab-modal dialogs. In this case, the
// notification is needed to let us draw attention to the dialog (i.e. // notification is needed to let us draw attention to the dialog (i.e.
...@@ -745,6 +675,9 @@ class RenderViewHostDelegate : public IPC::Channel::Listener { ...@@ -745,6 +675,9 @@ class RenderViewHostDelegate : public IPC::Channel::Listener {
int maximum_percent, int maximum_percent,
bool remember) {} bool remember) {}
// Notification that a worker process has crashed.
void WorkerCrashed() {}
protected: protected:
virtual ~RenderViewHostDelegate() {} virtual ~RenderViewHostDelegate() {}
}; };
......
...@@ -31,8 +31,6 @@ ...@@ -31,8 +31,6 @@
using base::Time; using base::Time;
namespace {
// NavigationControllerTest ---------------------------------------------------- // NavigationControllerTest ----------------------------------------------------
class NavigationControllerTest : public RenderViewHostTestHarness { class NavigationControllerTest : public RenderViewHostTestHarness {
...@@ -1824,14 +1822,9 @@ TEST_F(NavigationControllerTest, HistoryNavigate) { ...@@ -1824,14 +1822,9 @@ TEST_F(NavigationControllerTest, HistoryNavigate) {
controller().GoBack(); controller().GoBack();
contents()->CommitPendingNavigation(); contents()->CommitPendingNavigation();
// Casts the TabContents to a RenderViewHostDelegate::BrowserIntegration so we
// can call GoToEntryAtOffset which is private.
RenderViewHostDelegate::BrowserIntegration* rvh_delegate =
static_cast<RenderViewHostDelegate::BrowserIntegration*>(contents());
// Simulate the page calling history.back(), it should not create a pending // Simulate the page calling history.back(), it should not create a pending
// entry. // entry.
rvh_delegate->GoToEntryAtOffset(-1); contents()->OnGoToEntryAtOffset(-1);
EXPECT_EQ(-1, controller().pending_entry_index()); EXPECT_EQ(-1, controller().pending_entry_index());
// The actual cross-navigation is suspended until the current RVH tells us // The actual cross-navigation is suspended until the current RVH tells us
// it unloaded, simulate that. // it unloaded, simulate that.
...@@ -1846,7 +1839,7 @@ TEST_F(NavigationControllerTest, HistoryNavigate) { ...@@ -1846,7 +1839,7 @@ TEST_F(NavigationControllerTest, HistoryNavigate) {
process()->sink().ClearMessages(); process()->sink().ClearMessages();
// Now test history.forward() // Now test history.forward()
rvh_delegate->GoToEntryAtOffset(1); contents()->OnGoToEntryAtOffset(1);
EXPECT_EQ(-1, controller().pending_entry_index()); EXPECT_EQ(-1, controller().pending_entry_index());
// The actual cross-navigation is suspended until the current RVH tells us // The actual cross-navigation is suspended until the current RVH tells us
// it unloaded, simulate that. // it unloaded, simulate that.
...@@ -1858,7 +1851,7 @@ TEST_F(NavigationControllerTest, HistoryNavigate) { ...@@ -1858,7 +1851,7 @@ TEST_F(NavigationControllerTest, HistoryNavigate) {
process()->sink().ClearMessages(); process()->sink().ClearMessages();
// Make sure an extravagant history.go() doesn't break. // Make sure an extravagant history.go() doesn't break.
rvh_delegate->GoToEntryAtOffset(120); // Out of bounds. contents()->OnGoToEntryAtOffset(120); // Out of bounds.
EXPECT_EQ(-1, controller().pending_entry_index()); EXPECT_EQ(-1, controller().pending_entry_index());
message = process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID); message = process()->sink().GetFirstMessageMatching(ViewMsg_Navigate::ID);
EXPECT_TRUE(message == NULL); EXPECT_TRUE(message == NULL);
...@@ -2030,5 +2023,3 @@ TEST_F(NavigationControllerHistoryTest, NavigationPruning) { ...@@ -2030,5 +2023,3 @@ TEST_F(NavigationControllerHistoryTest, NavigationPruning) {
windows_[0]->tabs[0]->navigations[1]); windows_[0]->tabs[0]->navigations[1]);
} }
*/ */
} // namespace
...@@ -313,13 +313,8 @@ TEST_F(RenderViewHostManagerTest, PageDoesBackAndReload) { ...@@ -313,13 +313,8 @@ TEST_F(RenderViewHostManagerTest, PageDoesBackAndReload) {
contents()->NavigateAndCommit(url2); contents()->NavigateAndCommit(url2);
RenderViewHost* evil_rvh = contents()->render_view_host(); RenderViewHost* evil_rvh = contents()->render_view_host();
// Casts the TabContents to a RenderViewHostDelegate::BrowserIntegration so we
// can call GoToEntryAtOffset which is private.
RenderViewHostDelegate::BrowserIntegration* rvh_delegate =
static_cast<RenderViewHostDelegate::BrowserIntegration*>(contents());
// Now let's simulate the evil page calling history.back(). // Now let's simulate the evil page calling history.back().
rvh_delegate->GoToEntryAtOffset(-1); contents()->OnGoToEntryAtOffset(-1);
// We should have a new pending RVH. // We should have a new pending RVH.
// Note that in this case, the navigation has not committed, so evil_rvh will // Note that in this case, the navigation has not committed, so evil_rvh will
// not be deleted yet. // not be deleted yet.
......
...@@ -620,6 +620,21 @@ bool TabContents::OnMessageReceived(const IPC::Message& message) { ...@@ -620,6 +620,21 @@ bool TabContents::OnMessageReceived(const IPC::Message& message) {
OnUpdateContentRestrictions) OnUpdateContentRestrictions)
IPC_MESSAGE_HANDLER(ViewHostMsg_PDFHasUnsupportedFeature, IPC_MESSAGE_HANDLER(ViewHostMsg_PDFHasUnsupportedFeature,
OnPDFHasUnsupportedFeature) OnPDFHasUnsupportedFeature)
IPC_MESSAGE_HANDLER(ViewHostMsg_Find_Reply, OnFindReply)
IPC_MESSAGE_HANDLER(ViewHostMsg_GoToEntryAtOffset, OnGoToEntryAtOffset)
IPC_MESSAGE_HANDLER(ViewHostMsg_MissingPluginStatus, OnMissingPluginStatus)
IPC_MESSAGE_HANDLER(ViewHostMsg_CrashedPlugin, OnCrashedPlugin)
IPC_MESSAGE_HANDLER(ViewHostMsg_BlockedOutdatedPlugin,
OnBlockedOutdatedPlugin)
IPC_MESSAGE_HANDLER(ViewHostMsg_DidGetApplicationInfo,
OnDidGetApplicationInfo)
IPC_MESSAGE_HANDLER(ViewHostMsg_InstallApplication,
OnInstallApplication)
IPC_MESSAGE_HANDLER(ViewHostMsg_PageContents, OnPageContents)
IPC_MESSAGE_HANDLER(ViewHostMsg_PageTranslated, OnPageTranslated)
IPC_MESSAGE_HANDLER(ViewHostMsg_SetSuggestions, OnSetSuggestions)
IPC_MESSAGE_HANDLER(ViewHostMsg_InstantSupportDetermined,
OnInstantSupportDetermined)
IPC_MESSAGE_UNHANDLED(handled = false) IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP_EX() IPC_END_MESSAGE_MAP_EX()
...@@ -2241,30 +2256,16 @@ void TabContents::GenerateKeywordIfNecessary( ...@@ -2241,30 +2256,16 @@ void TabContents::GenerateKeywordIfNecessary(
url_model->Add(new_url); url_model->Add(new_url);
} }
void TabContents::OnUserGesture() {
// See comment in RenderViewHostDelegate::OnUserGesture as to why we do this.
DownloadRequestLimiter* limiter =
g_browser_process->download_request_limiter();
if (limiter)
limiter->OnUserGesture(this);
ExternalProtocolHandler::PermitLaunchUrl();
}
void TabContents::OnFindReply(int request_id, void TabContents::OnFindReply(int request_id,
int number_of_matches, int number_of_matches,
const gfx::Rect& selection_rect, const gfx::Rect& selection_rect,
int active_match_ordinal, int active_match_ordinal,
bool final_update) { bool final_update) {
// Ignore responses for requests that have been aborted. // Ignore responses for requests that have been aborted.
if (find_op_aborted_)
return;
// Ignore responses for requests other than the one we have most recently // Ignore responses for requests other than the one we have most recently
// issued. That way we won't act on stale results when the user has // issued. That way we won't act on stale results when the user has
// already typed in another query. // already typed in another query.
if (request_id != current_find_request_id_) if (!find_op_aborted_ && request_id == current_find_request_id_) {
return;
if (number_of_matches == -1) if (number_of_matches == -1)
number_of_matches = last_search_result_.number_of_matches(); number_of_matches = last_search_result_.number_of_matches();
if (active_match_ordinal == -1) if (active_match_ordinal == -1)
...@@ -2276,16 +2277,26 @@ void TabContents::OnFindReply(int request_id, ...@@ -2276,16 +2277,26 @@ void TabContents::OnFindReply(int request_id,
// Notify the UI, automation and any other observers that a find result was // Notify the UI, automation and any other observers that a find result was
// found. // found.
last_search_result_ = FindNotificationDetails(request_id, number_of_matches, last_search_result_ = FindNotificationDetails(
selection, active_match_ordinal, request_id, number_of_matches, selection, active_match_ordinal,
final_update); final_update);
NotificationService::current()->Notify( NotificationService::current()->Notify(
NotificationType::FIND_RESULT_AVAILABLE, NotificationType::FIND_RESULT_AVAILABLE,
Source<TabContents>(this), Source<TabContents>(this),
Details<FindNotificationDetails>(&last_search_result_)); Details<FindNotificationDetails>(&last_search_result_));
}
// 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.
render_view_host()->Send(new ViewMsg_FindReplyACK(
render_view_host()->routing_id()));
} }
void TabContents::GoToEntryAtOffset(int offset) { void TabContents::OnGoToEntryAtOffset(int offset) {
if (!delegate_ || delegate_->OnGoToEntryOffset(offset)) { if (!delegate_ || delegate_->OnGoToEntryOffset(offset)) {
NavigationEntry* entry = controller_.GetEntryAtOffset(offset); NavigationEntry* entry = controller_.GetEntryAtOffset(offset);
if (!entry) if (!entry)
...@@ -2330,11 +2341,6 @@ void TabContents::OnCrashedPlugin(const FilePath& plugin_path) { ...@@ -2330,11 +2341,6 @@ void TabContents::OnCrashedPlugin(const FilePath& plugin_path) {
WideToUTF16Hack(plugin_name)), true)); WideToUTF16Hack(plugin_name)), true));
} }
void TabContents::OnCrashedWorker() {
AddInfoBar(new SimpleAlertInfoBarDelegate(this, NULL,
l10n_util::GetStringUTF16(IDS_WEBWORKER_CRASHED_PROMPT), true));
}
void TabContents::OnDidGetApplicationInfo(int32 page_id, void TabContents::OnDidGetApplicationInfo(int32 page_id,
const WebApplicationInfo& info) { const WebApplicationInfo& info) {
web_app_info_ = info; web_app_info_ = info;
...@@ -2354,7 +2360,6 @@ void TabContents::OnBlockedOutdatedPlugin(const string16& name, ...@@ -2354,7 +2360,6 @@ void TabContents::OnBlockedOutdatedPlugin(const string16& name,
} }
void TabContents::OnPageContents(const GURL& url, void TabContents::OnPageContents(const GURL& url,
int renderer_process_id,
int32 page_id, int32 page_id,
const string16& contents, const string16& contents,
const std::string& language, const std::string& language,
...@@ -2432,11 +2437,6 @@ TabContents::GetRendererManagementDelegate() { ...@@ -2432,11 +2437,6 @@ TabContents::GetRendererManagementDelegate() {
return &render_manager_; return &render_manager_;
} }
RenderViewHostDelegate::BrowserIntegration*
TabContents::GetBrowserIntegrationDelegate() {
return this;
}
RenderViewHostDelegate::ContentSettings* RenderViewHostDelegate::ContentSettings*
TabContents::GetContentSettingsDelegate() { TabContents::GetContentSettingsDelegate() {
return content_settings_delegate_.get(); return content_settings_delegate_.get();
...@@ -3053,6 +3053,15 @@ WebPreferences TabContents::GetWebkitPrefs() { ...@@ -3053,6 +3053,15 @@ WebPreferences TabContents::GetWebkitPrefs() {
return web_prefs; return web_prefs;
} }
void TabContents::OnUserGesture() {
// See comment in RenderViewHostDelegate::OnUserGesture as to why we do this.
DownloadRequestLimiter* limiter =
g_browser_process->download_request_limiter();
if (limiter)
limiter->OnUserGesture(this);
ExternalProtocolHandler::PermitLaunchUrl();
}
void TabContents::OnIgnoredUIEvent() { void TabContents::OnIgnoredUIEvent() {
if (constrained_window_count()) { if (constrained_window_count()) {
ConstrainedWindow* window = *constrained_window_begin(); ConstrainedWindow* window = *constrained_window_begin();
...@@ -3144,6 +3153,11 @@ void TabContents::UpdateZoomLimits(int minimum_percent, ...@@ -3144,6 +3153,11 @@ void TabContents::UpdateZoomLimits(int minimum_percent,
temporary_zoom_settings_ = !remember; temporary_zoom_settings_ = !remember;
} }
void TabContents::WorkerCrashed() {
AddInfoBar(new SimpleAlertInfoBarDelegate(this, NULL,
l10n_util::GetStringUTF16(IDS_WEBWORKER_CRASHED_PROMPT), true));
}
void TabContents::BeforeUnloadFiredFromRenderManager( void TabContents::BeforeUnloadFiredFromRenderManager(
bool proceed, bool proceed,
bool* proceed_to_fire_unload) { bool* proceed_to_fire_unload) {
......
...@@ -89,7 +89,6 @@ struct WebPreferences; ...@@ -89,7 +89,6 @@ struct WebPreferences;
class TabContents : public PageNavigator, class TabContents : public PageNavigator,
public NotificationObserver, public NotificationObserver,
public RenderViewHostDelegate, public RenderViewHostDelegate,
public RenderViewHostDelegate::BrowserIntegration,
public RenderViewHostManager::Delegate, public RenderViewHostManager::Delegate,
public JavaScriptAppModalDialogDelegate, public JavaScriptAppModalDialogDelegate,
public ImageLoadingTracker::Observer, public ImageLoadingTracker::Observer,
...@@ -764,6 +763,8 @@ class TabContents : public PageNavigator, ...@@ -764,6 +763,8 @@ class TabContents : public PageNavigator,
FRIEND_TEST_ALL_PREFIXES(TabContentsTest, UpdateTitle); FRIEND_TEST_ALL_PREFIXES(TabContentsTest, UpdateTitle);
FRIEND_TEST_ALL_PREFIXES(TabContentsTest, CrossSiteCantPreemptAfterUnload); FRIEND_TEST_ALL_PREFIXES(TabContentsTest, CrossSiteCantPreemptAfterUnload);
FRIEND_TEST_ALL_PREFIXES(FormStructureBrowserTest, HTMLFiles); FRIEND_TEST_ALL_PREFIXES(FormStructureBrowserTest, HTMLFiles);
FRIEND_TEST_ALL_PREFIXES(NavigationControllerTest, HistoryNavigate);
FRIEND_TEST_ALL_PREFIXES(RenderViewHostManagerTest, PageDoesBackAndReload);
// Temporary until the view/contents separation is complete. // Temporary until the view/contents separation is complete.
friend class TabContentsView; friend class TabContentsView;
...@@ -811,6 +812,30 @@ class TabContents : public PageNavigator, ...@@ -811,6 +812,30 @@ class TabContents : public PageNavigator,
void OnUpdateContentRestrictions(int restrictions); void OnUpdateContentRestrictions(int restrictions);
void OnPDFHasUnsupportedFeature(); void OnPDFHasUnsupportedFeature();
void OnFindReply(int request_id,
int number_of_matches,
const gfx::Rect& selection_rect,
int active_match_ordinal,
bool final_update);
void OnGoToEntryAtOffset(int offset);
void OnMissingPluginStatus(int status);
void OnCrashedPlugin(const FilePath& plugin_path);
void OnDidGetApplicationInfo(int32 page_id, const WebApplicationInfo& info);
void OnInstallApplication(const WebApplicationInfo& info);
void OnBlockedOutdatedPlugin(const string16& name, const GURL& update_url);
void OnPageContents(const GURL& url,
int32 page_id,
const string16& contents,
const std::string& language,
bool page_translatable);
void OnPageTranslated(int32 page_id,
const std::string& original_lang,
const std::string& translated_lang,
TranslateErrors::Type error_type);
void OnSetSuggestions(int32 page_id,
const std::vector<std::string>& suggestions);
void OnInstantSupportDetermined(int32 page_id, bool result);
// Changes the IsLoading state and notifies delegate as needed // Changes the IsLoading state and notifies delegate as needed
// |details| is used to provide details on the load that just finished // |details| is used to provide details on the load that just finished
// (but can be null if not applicable). Can be overridden. // (but can be null if not applicable). Can be overridden.
...@@ -916,42 +941,10 @@ class TabContents : public PageNavigator, ...@@ -916,42 +941,10 @@ class TabContents : public PageNavigator,
// RenderViewHostDelegate ---------------------------------------------------- // RenderViewHostDelegate ----------------------------------------------------
// RenderViewHostDelegate::BrowserIntegration implementation.
virtual void OnUserGesture();
virtual void OnFindReply(int request_id,
int number_of_matches,
const gfx::Rect& selection_rect,
int active_match_ordinal,
bool final_update);
virtual void GoToEntryAtOffset(int offset);
virtual void OnMissingPluginStatus(int status);
virtual void OnCrashedPlugin(const FilePath& plugin_path);
virtual void OnCrashedWorker();
virtual void OnDidGetApplicationInfo(int32 page_id,
const WebApplicationInfo& info);
virtual void OnInstallApplication(const WebApplicationInfo& info);
virtual void OnBlockedOutdatedPlugin(const string16& name,
const GURL& update_url);
virtual void OnPageContents(const GURL& url,
int renderer_process_id,
int32 page_id,
const string16& contents,
const std::string& language,
bool page_translatable);
virtual void OnPageTranslated(int32 page_id,
const std::string& original_lang,
const std::string& translated_lang,
TranslateErrors::Type error_type);
virtual void OnSetSuggestions(int32 page_id,
const std::vector<std::string>& suggestions);
virtual void OnInstantSupportDetermined(int32 page_id, bool result);
// RenderViewHostDelegate implementation. // RenderViewHostDelegate implementation.
virtual RenderViewHostDelegate::View* GetViewDelegate(); virtual RenderViewHostDelegate::View* GetViewDelegate();
virtual RenderViewHostDelegate::RendererManagement* virtual RenderViewHostDelegate::RendererManagement*
GetRendererManagementDelegate(); GetRendererManagementDelegate();
virtual RenderViewHostDelegate::BrowserIntegration*
GetBrowserIntegrationDelegate();
virtual RenderViewHostDelegate::ContentSettings* GetContentSettingsDelegate(); virtual RenderViewHostDelegate::ContentSettings* GetContentSettingsDelegate();
virtual RenderViewHostDelegate::Save* GetSaveDelegate(); virtual RenderViewHostDelegate::Save* GetSaveDelegate();
virtual RenderViewHostDelegate::Printing* GetPrintingDelegate(); virtual RenderViewHostDelegate::Printing* GetPrintingDelegate();
...@@ -1020,6 +1013,7 @@ class TabContents : public PageNavigator, ...@@ -1020,6 +1013,7 @@ class TabContents : public PageNavigator,
virtual GURL GetAlternateErrorPageURL() const; virtual GURL GetAlternateErrorPageURL() const;
virtual RendererPreferences GetRendererPrefs(Profile* profile) const; virtual RendererPreferences GetRendererPrefs(Profile* profile) const;
virtual WebPreferences GetWebkitPrefs(); virtual WebPreferences GetWebkitPrefs();
virtual void OnUserGesture();
virtual void OnIgnoredUIEvent(); virtual void OnIgnoredUIEvent();
virtual void OnJSOutOfMemory(); virtual void OnJSOutOfMemory();
virtual void OnCrossSiteResponse(int new_render_process_host_id, virtual void OnCrossSiteResponse(int new_render_process_host_id,
...@@ -1035,6 +1029,7 @@ class TabContents : public PageNavigator, ...@@ -1035,6 +1029,7 @@ class TabContents : public PageNavigator,
virtual void UpdateZoomLimits(int minimum_percent, virtual void UpdateZoomLimits(int minimum_percent,
int maximum_percent, int maximum_percent,
bool remember); bool remember);
virtual void WorkerCrashed();
// RenderViewHostManager::Delegate ------------------------------------------- // RenderViewHostManager::Delegate -------------------------------------------
......
...@@ -419,9 +419,8 @@ void Navigate(NavigateParams* params) { ...@@ -419,9 +419,8 @@ void Navigate(NavigateParams* params) {
} }
if (user_initiated) { if (user_initiated) {
RenderViewHostDelegate::BrowserIntegration* integration = static_cast<RenderViewHostDelegate*>(params->target_contents->
params->target_contents->tab_contents(); tab_contents())->OnUserGesture();
integration->OnUserGesture();
} }
// Perform the actual navigation. // Perform the actual navigation.
......
...@@ -75,12 +75,8 @@ class WorkerCrashTask : public Task { ...@@ -75,12 +75,8 @@ class WorkerCrashTask : public Task {
void Run() { void Run() {
RenderViewHost* host = RenderViewHost* host =
RenderViewHost::FromID(render_process_unique_id_, render_view_id_); RenderViewHost::FromID(render_process_unique_id_, render_view_id_);
if (host) { if (host)
RenderViewHostDelegate::BrowserIntegration* integration_delegate = host->delegate()->WorkerCrashed();
host->delegate()->GetBrowserIntegrationDelegate();
if (integration_delegate)
integration_delegate->OnCrashedWorker();
}
} }
private: private:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment