summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-16 23:59:17 +0000
committertommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-16 23:59:17 +0000
commit35f13ab63b056a8e36c06e41655684915c183701 (patch)
tree913426da932aa18f73f44950d50b1de0398c3968
parentd65f129bee77d3a4f6ac186641fe11fd890ef077 (diff)
downloadchromium_src-35f13ab63b056a8e36c06e41655684915c183701.zip
chromium_src-35f13ab63b056a8e36c06e41655684915c183701.tar.gz
chromium_src-35f13ab63b056a8e36c06e41655684915c183701.tar.bz2
Handle right-click->"Save Link As" in the host browser.
TEST=Right click on a link in CF and select "save link as". You should immediately get the host browser's download UI. Before there could be a significant wait before this happened. BUG=23561 Review URL: http://codereview.chromium.org/506042 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@34783 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/external_tab_container.cc23
-rw-r--r--chrome/test/automation/automation_messages.h71
-rw-r--r--chrome/test/automation/automation_messages_internal.h7
-rw-r--r--chrome_frame/chrome_active_document.cc5
-rw-r--r--chrome_frame/chrome_active_document.h2
-rw-r--r--chrome_frame/chrome_frame_activex_base.h18
-rw-r--r--chrome_frame/chrome_frame_delegate.h3
-rw-r--r--chrome_frame/chrome_frame_npapi.cc3
-rw-r--r--chrome_frame/chrome_frame_npapi.h2
-rw-r--r--chrome_frame/chrome_frame_plugin.h11
-rw-r--r--chrome_frame/test/chrome_frame_unittests.cc4
-rw-r--r--chrome_frame/utils.cc19
-rw-r--r--chrome_frame/utils.h3
13 files changed, 151 insertions, 20 deletions
diff --git a/chrome/browser/external_tab_container.cc b/chrome/browser/external_tab_container.cc
index 2a6c237..2775960 100644
--- a/chrome/browser/external_tab_container.cc
+++ b/chrome/browser/external_tab_container.cc
@@ -440,11 +440,20 @@ bool ExternalTabContainer::HandleContextMenu(const ContextMenuParams& params) {
POINT screen_pt = { params.x, params.y };
MapWindowPoints(GetNativeView(), HWND_DESKTOP, &screen_pt, 1);
+ IPC::ContextMenuParams ipc_params;
+ ipc_params.screen_x = screen_pt.x;
+ ipc_params.screen_y = screen_pt.y;
+ ipc_params.link_url = params.link_url;
+ ipc_params.unfiltered_link_url = params.unfiltered_link_url;
+ ipc_params.src_url = params.src_url;
+ ipc_params.page_url = params.page_url;
+ ipc_params.frame_url = params.frame_url;
+
bool rtl = l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT;
automation_->Send(
new AutomationMsg_ForwardContextMenuToExternalHost(0, tab_handle_,
- external_context_menu_->GetMenuHandle(), screen_pt.x, screen_pt.y,
- rtl ? TPM_RIGHTALIGN : TPM_LEFTALIGN));
+ external_context_menu_->GetMenuHandle(),
+ rtl ? TPM_RIGHTALIGN : TPM_LEFTALIGN, ipc_params));
return true;
}
@@ -455,6 +464,16 @@ bool ExternalTabContainer::ExecuteContextMenuCommand(int command) {
return false;
}
+ switch (command) {
+ case IDS_CONTENT_CONTEXT_SAVEAUDIOAS:
+ case IDS_CONTENT_CONTEXT_SAVEVIDEOAS:
+ case IDS_CONTENT_CONTEXT_SAVEIMAGEAS:
+ case IDS_CONTENT_CONTEXT_SAVELINKAS: {
+ NOTREACHED(); // Should be handled in host.
+ break;
+ }
+ }
+
external_context_menu_->ExecuteCommand(command);
return true;
}
diff --git a/chrome/test/automation/automation_messages.h b/chrome/test/automation/automation_messages.h
index 388b6f2..b7f3013 100644
--- a/chrome/test/automation/automation_messages.h
+++ b/chrome/test/automation/automation_messages.h
@@ -454,6 +454,77 @@ struct ParamTraits<NavigationInfo> {
}
};
+// A stripped down version of ContextMenuParams in webkit/glue/context_menu.h.
+struct ContextMenuParams {
+ // The x coordinate for displaying the menu.
+ int screen_x;
+
+ // The y coordinate for displaying the menu.
+ int screen_y;
+
+ // This is the URL of the link that encloses the node the context menu was
+ // invoked on.
+ GURL link_url;
+
+ // The link URL to be used ONLY for "copy link address". We don't validate
+ // this field in the frontend process.
+ GURL unfiltered_link_url;
+
+ // This is the source URL for the element that the context menu was
+ // invoked on. Example of elements with source URLs are img, audio, and
+ // video.
+ GURL src_url;
+
+ // This is the URL of the top level page that the context menu was invoked
+ // on.
+ GURL page_url;
+
+ // This is the URL of the subframe that the context menu was invoked on.
+ GURL frame_url;
+};
+
+// Traits for ContextMenuParams structure to pack/unpack.
+template <>
+struct ParamTraits<ContextMenuParams> {
+ typedef ContextMenuParams param_type;
+ static void Write(Message* m, const param_type& p) {
+ WriteParam(m, p.screen_x);
+ WriteParam(m, p.screen_y);
+ WriteParam(m, p.link_url);
+ WriteParam(m, p.unfiltered_link_url);
+ WriteParam(m, p.src_url);
+ WriteParam(m, p.page_url);
+ WriteParam(m, p.frame_url);
+ }
+ static bool Read(const Message* m, void** iter, param_type* p) {
+ return ReadParam(m, iter, &p->screen_x) &&
+ ReadParam(m, iter, &p->screen_y) &&
+ ReadParam(m, iter, &p->link_url) &&
+ ReadParam(m, iter, &p->unfiltered_link_url) &&
+ ReadParam(m, iter, &p->src_url) &&
+ ReadParam(m, iter, &p->page_url) &&
+ ReadParam(m, iter, &p->frame_url);
+ }
+ static void Log(const param_type& p, std::wstring* l) {
+ l->append(L"(");
+ LogParam(p.screen_x, l);
+ l->append(L", ");
+ LogParam(p.screen_y, l);
+ l->append(L", ");
+ LogParam(p.link_url, l);
+ l->append(L", ");
+ LogParam(p.unfiltered_link_url, l);
+ l->append(L", ");
+ LogParam(p.src_url, l);
+ l->append(L", ");
+ LogParam(p.page_url, l);
+ l->append(L", ");
+ LogParam(p.frame_url, l);
+ l->append(L")");
+ }
+};
+
+
} // namespace IPC
#define MESSAGES_INTERNAL_FILE \
diff --git a/chrome/test/automation/automation_messages_internal.h b/chrome/test/automation/automation_messages_internal.h
index 754c335..b90280b 100644
--- a/chrome/test/automation/automation_messages_internal.h
+++ b/chrome/test/automation/automation_messages_internal.h
@@ -944,12 +944,11 @@ IPC_BEGIN_MESSAGES(Automation)
string16 /* chrome_locale */)
#if defined(OS_WIN)
- IPC_MESSAGE_ROUTED5(AutomationMsg_ForwardContextMenuToExternalHost,
+ IPC_MESSAGE_ROUTED4(AutomationMsg_ForwardContextMenuToExternalHost,
int /* tab_handle */,
HANDLE /* source menu handle */,
- int /* the x coordinate for displaying the menu */,
- int /* the y coordinate for displaying the menu */,
- int /* align flags */)
+ int /* align flags */,
+ IPC::ContextMenuParams /* params */)
IPC_MESSAGE_ROUTED2(AutomationMsg_ForwardContextMenuCommandToChrome,
int /* tab_handle */,
diff --git a/chrome_frame/chrome_active_document.cc b/chrome_frame/chrome_active_document.cc
index d03a6f5..79253d1 100644
--- a/chrome_frame/chrome_active_document.cc
+++ b/chrome_frame/chrome_active_document.cc
@@ -715,7 +715,8 @@ bool ChromeActiveDocument::PreProcessContextMenu(HMENU menu) {
return Base::PreProcessContextMenu(menu);
}
-bool ChromeActiveDocument::HandleContextMenuCommand(UINT cmd) {
+bool ChromeActiveDocument::HandleContextMenuCommand(UINT cmd,
+ const IPC::ContextMenuParams& params) {
ScopedComPtr<IWebBrowser2> web_browser2;
DoQueryService(SID_SWebBrowserApp, m_spClientSite, web_browser2.Receive());
@@ -733,7 +734,7 @@ bool ChromeActiveDocument::HandleContextMenuCommand(UINT cmd) {
break;
default:
- return Base::HandleContextMenuCommand(cmd);
+ return Base::HandleContextMenuCommand(cmd, params);
}
return true;
diff --git a/chrome_frame/chrome_active_document.h b/chrome_frame/chrome_active_document.h
index dbd430f..6b57f2e 100644
--- a/chrome_frame/chrome_active_document.h
+++ b/chrome_frame/chrome_active_document.h
@@ -236,7 +236,7 @@ END_EXEC_COMMAND_MAP()
// Callbacks from ChromeFramePlugin<T>
bool PreProcessContextMenu(HMENU menu);
- bool HandleContextMenuCommand(UINT cmd);
+ bool HandleContextMenuCommand(UINT cmd, const IPC::ContextMenuParams& params);
// Should connections initiated by this class try to block
// responses served with the X-Frame-Options header?
diff --git a/chrome_frame/chrome_frame_activex_base.h b/chrome_frame/chrome_frame_activex_base.h
index 6a7183f..28ca868 100644
--- a/chrome_frame/chrome_frame_activex_base.h
+++ b/chrome_frame/chrome_frame_activex_base.h
@@ -40,6 +40,7 @@
#include "chrome_frame/com_message_event.h"
#include "chrome_frame/com_type_info_holder.h"
#include "chrome_frame/urlmon_url_request.h"
+#include "grit/generated_resources.h"
// Include without path to make GYP build see it.
#include "chrome_tab.h" // NOLINT
@@ -288,11 +289,26 @@ END_MSG_MAP()
return CComControlBase::IOleObject_SetClientSite(client_site);
}
- bool HandleContextMenuCommand(UINT cmd) {
+ bool HandleContextMenuCommand(UINT cmd,
+ const IPC::ContextMenuParams& params) {
if (cmd == IDC_ABOUT_CHROME_FRAME) {
int tab_handle = automation_client_->tab()->handle();
OnOpenURL(tab_handle, GURL("about:version"), GURL(), NEW_WINDOW);
return true;
+ } else {
+ switch (cmd) {
+ case IDS_CONTENT_CONTEXT_SAVEAUDIOAS:
+ case IDS_CONTENT_CONTEXT_SAVEVIDEOAS:
+ case IDS_CONTENT_CONTEXT_SAVEIMAGEAS:
+ case IDS_CONTENT_CONTEXT_SAVELINKAS: {
+ const GURL& referrer = params.frame_url.is_empty() ?
+ params.page_url : params.frame_url;
+ const GURL& url = (cmd == IDS_CONTENT_CONTEXT_SAVELINKAS ?
+ params.link_url : params.src_url);
+ DoFileDownloadInIE(UTF8ToWide(url.spec()).c_str());
+ return true;
+ }
+ }
}
return false;
diff --git a/chrome_frame/chrome_frame_delegate.h b/chrome_frame/chrome_frame_delegate.h
index 1742ad0..49ae1c1 100644
--- a/chrome_frame/chrome_frame_delegate.h
+++ b/chrome_frame/chrome_frame_delegate.h
@@ -91,7 +91,8 @@ class ChromeFrameDelegateImpl : public ChromeFrameDelegate {
const std::string& origin,
const std::string& target) {}
virtual void OnHandleContextMenu(int tab_handle, HANDLE menu_handle,
- int x_pos, int y_pos, int align_flags) {}
+ int align_flags,
+ const IPC::ContextMenuParams& params) {}
virtual void OnRequestStart(int tab_handle, int request_id,
const IPC::AutomationURLRequest& request) {}
virtual void OnRequestRead(int tab_handle, int request_id,
diff --git a/chrome_frame/chrome_frame_npapi.cc b/chrome_frame/chrome_frame_npapi.cc
index 509f083..d3e1f91 100644
--- a/chrome_frame/chrome_frame_npapi.cc
+++ b/chrome_frame/chrome_frame_npapi.cc
@@ -1605,7 +1605,8 @@ NPAPIUrlRequest* ChromeFrameNPAPI::RequestFromNotifyData(
return request;
}
-bool ChromeFrameNPAPI::HandleContextMenuCommand(UINT cmd) {
+bool ChromeFrameNPAPI::HandleContextMenuCommand(UINT cmd,
+ const IPC::ContextMenuParams& params) {
if (cmd == IDC_ABOUT_CHROME_FRAME) {
// TODO: implement "About Chrome Frame"
}
diff --git a/chrome_frame/chrome_frame_npapi.h b/chrome_frame/chrome_frame_npapi.h
index 1d35b4c..45b4028 100644
--- a/chrome_frame/chrome_frame_npapi.h
+++ b/chrome_frame/chrome_frame_npapi.h
@@ -125,7 +125,7 @@ END_MSG_MAP()
// Initialize string->identifier mapping, public to allow unittesting.
static void InitializeIdentifiers();
- bool HandleContextMenuCommand(UINT cmd);
+ bool HandleContextMenuCommand(UINT cmd, const IPC::ContextMenuParams& params);
protected:
// Handler for accelerator messages passed on from the hosted chrome
// instance.
diff --git a/chrome_frame/chrome_frame_plugin.h b/chrome_frame/chrome_frame_plugin.h
index 36f2fc2..0e16001 100644
--- a/chrome_frame/chrome_frame_plugin.h
+++ b/chrome_frame/chrome_frame_plugin.h
@@ -93,7 +93,8 @@ END_MSG_MAP()
}
virtual void OnHandleContextMenu(int tab_handle, HANDLE menu_handle,
- int x_pos, int y_pos, int align_flags) {
+ int align_flags,
+ const IPC::ContextMenuParams& params) {
if (!menu_handle || !automation_client_.get()) {
NOTREACHED();
return;
@@ -109,9 +110,9 @@ END_MSG_MAP()
T* pThis = static_cast<T*>(this);
if (pThis->PreProcessContextMenu(copy)) {
UINT flags = align_flags | TPM_LEFTBUTTON | TPM_RETURNCMD | TPM_RECURSE;
- UINT selected = TrackPopupMenuEx(copy, flags, x_pos, y_pos, GetWindow(),
- NULL);
- if (selected != 0 && !pThis->HandleContextMenuCommand(selected)) {
+ UINT selected = TrackPopupMenuEx(copy, flags, params.screen_x,
+ params.screen_y, GetWindow(), NULL);
+ if (selected != 0 && !pThis->HandleContextMenuCommand(selected, params)) {
automation_client_->SendContextMenuCommandToChromeFrame(selected);
}
}
@@ -175,7 +176,7 @@ END_MSG_MAP()
// Return true if menu command is processed, otherwise the command will be
// passed to Chrome for execution. Override in most-derived class if needed.
- bool HandleContextMenuCommand(UINT cmd) {
+ bool HandleContextMenuCommand(UINT cmd, const IPC::ContextMenuParams& params) {
return false;
}
diff --git a/chrome_frame/test/chrome_frame_unittests.cc b/chrome_frame/test/chrome_frame_unittests.cc
index 1b4eaee..fc4fd1a 100644
--- a/chrome_frame/test/chrome_frame_unittests.cc
+++ b/chrome_frame/test/chrome_frame_unittests.cc
@@ -714,8 +714,8 @@ struct MockCFDelegate : public ChromeFrameDelegateImpl {
const std::string& message,
const std::string& origin,
const std::string& target));
- MOCK_METHOD5(OnHandleContextMenu, void(int tab_handle, HANDLE menu_handle,
- int x_pos, int y_pos, int align_flags));
+ MOCK_METHOD4(OnHandleContextMenu, void(int tab_handle, HANDLE menu_handle,
+ int align_flags, const IPC::ContextMenuParams& params));
MOCK_METHOD3(OnRequestStart, void(int tab_handle, int request_id,
const IPC::AutomationURLRequest& request));
MOCK_METHOD3(OnRequestRead, void(int tab_handle, int request_id,
diff --git a/chrome_frame/utils.cc b/chrome_frame/utils.cc
index be955bf..88b46c5 100644
--- a/chrome_frame/utils.cc
+++ b/chrome_frame/utils.cc
@@ -415,6 +415,25 @@ bool IsIEInPrivate() {
return incognito_mode;
}
+HRESULT DoFileDownloadInIE(const wchar_t* url) {
+ DCHECK(url);
+
+ HMODULE mod = ::GetModuleHandleA("ieframe.dll");
+ if (!mod)
+ mod = ::GetModuleHandleA("shdocvw.dll");
+
+ if (!mod) {
+ NOTREACHED();
+ return E_UNEXPECTED;
+ }
+
+ typedef HRESULT (WINAPI* DoFileDownloadFn)(const wchar_t*);
+ DoFileDownloadFn fn = reinterpret_cast<DoFileDownloadFn>(
+ ::GetProcAddress(mod, "DoFileDownload"));
+ DCHECK(fn);
+ return fn ? fn(url) : E_UNEXPECTED;
+}
+
bool GetModuleVersion(HMODULE module, uint32* high, uint32* low) {
DCHECK(module != NULL)
<< "Please use GetModuleHandle(NULL) to get the process name";
diff --git a/chrome_frame/utils.h b/chrome_frame/utils.h
index 8750794..d10b7c0 100644
--- a/chrome_frame/utils.h
+++ b/chrome_frame/utils.h
@@ -165,6 +165,9 @@ bool GetModuleVersion(HMODULE module, uint32* high, uint32* low);
// whether current process is IEXPLORE.
bool IsIEInPrivate();
+// Calls [ieframe|shdocvw]!DoFileDownload to initiate a download.
+HRESULT DoFileDownloadInIE(const wchar_t* url);
+
// Creates a copy of a menu. We need this when original menu comes from
// a process with higher integrity.
HMENU UtilCloneContextMenu(HMENU original_menu);