Skip to content

Commit

Permalink
Handle right-click->"Save Link As" in the host browser.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
tommi@chromium.org committed Dec 16, 2009
1 parent d65f129 commit 35f13ab
Show file tree
Hide file tree
Showing 13 changed files with 151 additions and 20 deletions.
23 changes: 21 additions & 2 deletions chrome/browser/external_tab_container.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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;
}
Expand Down
71 changes: 71 additions & 0 deletions chrome/test/automation/automation_messages.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
7 changes: 3 additions & 4 deletions chrome/test/automation/automation_messages_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */,
Expand Down
5 changes: 3 additions & 2 deletions chrome_frame/chrome_active_document.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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());

Expand All @@ -733,7 +734,7 @@ bool ChromeActiveDocument::HandleContextMenuCommand(UINT cmd) {
break;

default:
return Base::HandleContextMenuCommand(cmd);
return Base::HandleContextMenuCommand(cmd, params);
}

return true;
Expand Down
2 changes: 1 addition & 1 deletion chrome_frame/chrome_active_document.h
Original file line number Diff line number Diff line change
Expand Up @@ -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?
Expand Down
18 changes: 17 additions & 1 deletion chrome_frame/chrome_frame_activex_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion chrome_frame/chrome_frame_delegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
3 changes: 2 additions & 1 deletion chrome_frame/chrome_frame_npapi.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
Expand Down
2 changes: 1 addition & 1 deletion chrome_frame/chrome_frame_npapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
11 changes: 6 additions & 5 deletions chrome_frame/chrome_frame_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
}
}
Expand Down Expand Up @@ -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;
}

Expand Down
4 changes: 2 additions & 2 deletions chrome_frame/test/chrome_frame_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
19 changes: 19 additions & 0 deletions chrome_frame/utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
3 changes: 3 additions & 0 deletions chrome_frame/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 35f13ab

Please sign in to comment.