mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-06-05 21:39:12 +02:00
Add drag and drop support for Windows (issue #140).
git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@194 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
16
cef.gyp
16
cef.gyp
@ -262,6 +262,7 @@
|
||||
'../ui/gfx/gfx.gyp:gfx',
|
||||
'../ui/gfx/gfx.gyp:gfx_resources',
|
||||
'../ui/ui.gyp:ui_base',
|
||||
'../views/views.gyp:views',
|
||||
'../webkit/support/webkit_support.gyp:appcache',
|
||||
'../webkit/support/webkit_support.gyp:blob',
|
||||
'../webkit/support/webkit_support.gyp:database',
|
||||
@ -502,6 +503,7 @@
|
||||
'../ui/gfx/gfx.gyp:gfx',
|
||||
'../ui/gfx/gfx.gyp:gfx_resources',
|
||||
'../ui/ui.gyp:ui_base',
|
||||
'../views/views.gyp:views',
|
||||
'../webkit/support/webkit_support.gyp:appcache',
|
||||
'../webkit/support/webkit_support.gyp:blob',
|
||||
'../webkit/support/webkit_support.gyp:database',
|
||||
@ -579,6 +581,8 @@
|
||||
'libcef/cef_string_types.cc',
|
||||
'libcef/cef_thread.cc',
|
||||
'libcef/cef_thread.h',
|
||||
'libcef/drag_download_file.cc',
|
||||
'libcef/drag_download_file.h',
|
||||
'libcef/dom_storage_area.cc',
|
||||
'libcef/dom_storage_area.h',
|
||||
'libcef/dom_storage_common.h',
|
||||
@ -624,10 +628,8 @@
|
||||
'sources': [
|
||||
'include/cef_types_win.h',
|
||||
'include/cef_win.h',
|
||||
'libcef/browser_drag_delegate.cc',
|
||||
'libcef/browser_drag_delegate.h',
|
||||
'libcef/browser_drop_delegate.cc',
|
||||
'libcef/browser_drop_delegate.h',
|
||||
'libcef/browser_drag_delegate_win.cc',
|
||||
'libcef/browser_drag_delegate_win.h',
|
||||
'libcef/browser_impl_win.cc',
|
||||
'libcef/browser_webkit_glue_win.cc',
|
||||
'libcef/browser_webview_delegate_win.cc',
|
||||
@ -637,6 +639,12 @@
|
||||
'libcef/printing/print_settings.h',
|
||||
'libcef/printing/win_printing_context.cc',
|
||||
'libcef/printing/win_printing_context.h',
|
||||
'libcef/web_drag_source_win.cc',
|
||||
'libcef/web_drag_source_win.h',
|
||||
'libcef/web_drag_utils_win.cc',
|
||||
'libcef/web_drag_utils_win.h',
|
||||
'libcef/web_drop_target_win.cc',
|
||||
'libcef/web_drop_target_win.h',
|
||||
'libcef/webview_host_win.cc',
|
||||
'libcef/webwidget_host_win.cc',
|
||||
],
|
||||
|
@ -1,42 +0,0 @@
|
||||
// Copyright (c) 2009 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 "browser_drag_delegate.h"
|
||||
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebPoint.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
|
||||
|
||||
using WebKit::WebPoint;
|
||||
using WebKit::WebView;
|
||||
|
||||
namespace {
|
||||
|
||||
void GetCursorPositions(HWND hwnd, gfx::Point* client, gfx::Point* screen) {
|
||||
// GetCursorPos will fail if the input desktop isn't the current desktop.
|
||||
// (0,0) is wrong, but better than uninitialized.
|
||||
// We should clean up all callers to handle failure -- http://b/1208177 .
|
||||
POINT pos;
|
||||
if (!GetCursorPos(&pos)) {
|
||||
pos.x = 0;
|
||||
pos.y = 0;
|
||||
}
|
||||
|
||||
*screen = gfx::Point(pos);
|
||||
ScreenToClient(hwnd, &pos);
|
||||
*client = gfx::Point(pos);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void BrowserDragDelegate::OnDragSourceCancel() {
|
||||
OnDragSourceDrop();
|
||||
}
|
||||
|
||||
void BrowserDragDelegate::OnDragSourceDrop() {
|
||||
gfx::Point client;
|
||||
gfx::Point screen;
|
||||
GetCursorPositions(source_hwnd_, &client, &screen);
|
||||
webview_->dragSourceEndedAt(client, screen, WebKit::WebDragOperationCopy);
|
||||
// TODO(snej): Pass the real drag operation instead
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
// Copyright (c) 2010 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 _BROWSER_DRAG_DELEGATE_H
|
||||
#define _BROWSER_DRAG_DELEGATE_H
|
||||
|
||||
#include "ui/base/dragdrop/drag_source.h"
|
||||
|
||||
namespace WebKit {
|
||||
class WebView;
|
||||
}
|
||||
|
||||
// A class that implements ui::DragSource for the browser webview
|
||||
// delegate.
|
||||
class BrowserDragDelegate : public ui::DragSource {
|
||||
public:
|
||||
BrowserDragDelegate(HWND source_hwnd, WebKit::WebView* webview)
|
||||
: ui::DragSource(),
|
||||
source_hwnd_(source_hwnd),
|
||||
webview_(webview) { }
|
||||
|
||||
protected:
|
||||
// ui::DragSource
|
||||
virtual void OnDragSourceCancel();
|
||||
virtual void OnDragSourceDrop();
|
||||
virtual void OnDragSourceMove();
|
||||
|
||||
private:
|
||||
WebKit::WebView* webview_;
|
||||
|
||||
// A HWND for the source we are associated with, used for translating
|
||||
// mouse coordinates from screen to client coordinates.
|
||||
HWND source_hwnd_;
|
||||
};
|
||||
|
||||
#endif // _BROWSER_DRAG_DELEGATE_H
|
||||
|
568
libcef/browser_drag_delegate_win.cc
Normal file
568
libcef/browser_drag_delegate_win.cc
Normal file
@ -0,0 +1,568 @@
|
||||
// Copyright (c) 2011 The Chromium Embedded Framework Authors.
|
||||
// Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "include/cef.h"
|
||||
#include "browser_drag_delegate_win.h"
|
||||
#include "browser_impl.h"
|
||||
#include "browser_webview_delegate.h"
|
||||
#include "cef_thread.h"
|
||||
#include "drag_download_file.h"
|
||||
#include "web_drag_source_win.h"
|
||||
#include "web_drag_utils_win.h"
|
||||
#include "web_drop_target_win.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/file_path.h"
|
||||
#include "base/message_loop.h"
|
||||
#include "base/string_util.h"
|
||||
#include "base/task.h"
|
||||
#include "base/threading/platform_thread.h"
|
||||
#include "base/threading/thread.h"
|
||||
#include "base/threading/thread_restrictions.h"
|
||||
#include "base/utf_string_conversions.h"
|
||||
#include "net/base/file_stream.h"
|
||||
#include "net/base/mime_util.h"
|
||||
#include "net/base/net_util.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
|
||||
#include "views/drag_utils.h"
|
||||
#include "webkit/glue/webdropdata.h"
|
||||
|
||||
using WebKit::WebDragOperationsMask;
|
||||
using WebKit::WebDragOperationCopy;
|
||||
using WebKit::WebDragOperationLink;
|
||||
using WebKit::WebDragOperationMove;
|
||||
using WebKit::WebView;
|
||||
|
||||
namespace {
|
||||
|
||||
HHOOK msg_hook = NULL;
|
||||
DWORD drag_out_thread_id = 0;
|
||||
bool mouse_up_received = false;
|
||||
|
||||
LRESULT CALLBACK MsgFilterProc(int code, WPARAM wparam, LPARAM lparam) {
|
||||
if (code == base::MessagePumpForUI::kMessageFilterCode &&
|
||||
!mouse_up_received) {
|
||||
MSG* msg = reinterpret_cast<MSG*>(lparam);
|
||||
// We do not care about WM_SYSKEYDOWN and WM_SYSKEYUP because when ALT key
|
||||
// is pressed down on drag-and-drop, it means to create a link.
|
||||
if (msg->message == WM_MOUSEMOVE || msg->message == WM_LBUTTONUP ||
|
||||
msg->message == WM_KEYDOWN || msg->message == WM_KEYUP) {
|
||||
// Forward the message from the UI thread to the drag-and-drop thread.
|
||||
PostThreadMessage(drag_out_thread_id,
|
||||
msg->message,
|
||||
msg->wParam,
|
||||
msg->lParam);
|
||||
|
||||
// If the left button is up, we do not need to forward the message any
|
||||
// more.
|
||||
if (msg->message == WM_LBUTTONUP || !(GetKeyState(VK_LBUTTON) & 0x8000))
|
||||
mouse_up_received = true;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return CallNextHookEx(msg_hook, code, wparam, lparam);
|
||||
}
|
||||
|
||||
// Parse the download metadata set in DataTransfer.setData. The metadata
|
||||
// consists of a set of the following values separated by ":"
|
||||
// * MIME type
|
||||
// * File name
|
||||
// * URL
|
||||
// If the file name contains special characters, they need to be escaped
|
||||
// appropriately.
|
||||
// For example, we can have
|
||||
// text/plain:example.txt:http://example.com/example.txt
|
||||
// From chrome/browser/download/drag_download_util.cc
|
||||
bool ParseDownloadMetadata(const string16& metadata,
|
||||
string16* mime_type,
|
||||
FilePath* file_name,
|
||||
GURL* url) {
|
||||
const char16 separator = L':';
|
||||
|
||||
size_t mime_type_end_pos = metadata.find(separator);
|
||||
if (mime_type_end_pos == string16::npos)
|
||||
return false;
|
||||
|
||||
size_t file_name_end_pos = metadata.find(separator, mime_type_end_pos + 1);
|
||||
if (file_name_end_pos == string16::npos)
|
||||
return false;
|
||||
|
||||
GURL parsed_url = GURL(metadata.substr(file_name_end_pos + 1));
|
||||
if (!parsed_url.is_valid())
|
||||
return false;
|
||||
|
||||
if (mime_type)
|
||||
*mime_type = metadata.substr(0, mime_type_end_pos);
|
||||
if (file_name) {
|
||||
string16 file_name_str = metadata.substr(
|
||||
mime_type_end_pos + 1, file_name_end_pos - mime_type_end_pos - 1);
|
||||
#if defined(OS_WIN)
|
||||
*file_name = FilePath(file_name_str);
|
||||
#else
|
||||
*file_name = FilePath(UTF16ToUTF8(file_name_str));
|
||||
#endif
|
||||
}
|
||||
if (url)
|
||||
*url = parsed_url;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Returns whether the specified extension is automatically integrated into the
|
||||
// windows shell.
|
||||
// From chrome/browser/download/download_util.cc
|
||||
bool IsShellIntegratedExtension(const string16& extension) {
|
||||
string16 extension_lower = StringToLowerASCII(extension);
|
||||
|
||||
static const wchar_t* const integrated_extensions[] = {
|
||||
// See <http://msdn.microsoft.com/en-us/library/ms811694.aspx>.
|
||||
L"local",
|
||||
// Right-clicking on shortcuts can be magical.
|
||||
L"lnk",
|
||||
};
|
||||
|
||||
for (int i = 0; i < arraysize(integrated_extensions); ++i) {
|
||||
if (extension_lower == integrated_extensions[i])
|
||||
return true;
|
||||
}
|
||||
|
||||
// See <http://www.juniper.net/security/auto/vulnerabilities/vuln2612.html>.
|
||||
// That vulnerability report is not exactly on point, but files become magical
|
||||
// if their end in a CLSID. Here we block extensions that look like CLSIDs.
|
||||
if (extension_lower.size() > 0 && extension_lower.at(0) == L'{' &&
|
||||
extension_lower.at(extension_lower.length() - 1) == L'}')
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns whether the specified file name is a reserved name on windows.
|
||||
// This includes names like "com2.zip" (which correspond to devices) and
|
||||
// desktop.ini and thumbs.db which have special meaning to the windows shell.
|
||||
// From chrome/browser/download/download_util.cc
|
||||
bool IsReservedName(const string16& filename) {
|
||||
// This list is taken from the MSDN article "Naming a file"
|
||||
// http://msdn2.microsoft.com/en-us/library/aa365247(VS.85).aspx
|
||||
// I also added clock$ because GetSaveFileName seems to consider it as a
|
||||
// reserved name too.
|
||||
static const wchar_t* const known_devices[] = {
|
||||
L"con", L"prn", L"aux", L"nul", L"com1", L"com2", L"com3", L"com4", L"com5",
|
||||
L"com6", L"com7", L"com8", L"com9", L"lpt1", L"lpt2", L"lpt3", L"lpt4",
|
||||
L"lpt5", L"lpt6", L"lpt7", L"lpt8", L"lpt9", L"clock$"
|
||||
};
|
||||
string16 filename_lower = StringToLowerASCII(filename);
|
||||
|
||||
for (int i = 0; i < arraysize(known_devices); ++i) {
|
||||
// Exact match.
|
||||
if (filename_lower == known_devices[i])
|
||||
return true;
|
||||
// Starts with "DEVICE.".
|
||||
if (filename_lower.find(string16(known_devices[i]) + L".") == 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
static const wchar_t* const magic_names[] = {
|
||||
// These file names are used by the "Customize folder" feature of the shell.
|
||||
L"desktop.ini",
|
||||
L"thumbs.db",
|
||||
};
|
||||
|
||||
for (int i = 0; i < arraysize(magic_names); ++i) {
|
||||
if (filename_lower == magic_names[i])
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif // OS_WIN
|
||||
|
||||
// Create an extension based on the file name and mime type.
|
||||
// From chrome/browser/download/download_util.cc
|
||||
void GenerateExtension(const FilePath& file_name,
|
||||
const std::string& mime_type,
|
||||
FilePath::StringType* generated_extension) {
|
||||
// We're worried about two things here:
|
||||
//
|
||||
// 1) Usability. If the site fails to provide a file extension, we want to
|
||||
// guess a reasonable file extension based on the content type.
|
||||
//
|
||||
// 2) Shell integration. Some file extensions automatically integrate with
|
||||
// the shell. We block these extensions to prevent a malicious web site
|
||||
// from integrating with the user's shell.
|
||||
|
||||
// See if our file name already contains an extension.
|
||||
FilePath::StringType extension = file_name.Extension();
|
||||
if (!extension.empty())
|
||||
extension.erase(extension.begin()); // Erase preceding '.'.
|
||||
|
||||
#if defined(OS_WIN)
|
||||
static const FilePath::CharType default_extension[] =
|
||||
FILE_PATH_LITERAL("download");
|
||||
|
||||
// Rename shell-integrated extensions.
|
||||
if (IsShellIntegratedExtension(extension))
|
||||
extension.assign(default_extension);
|
||||
#endif
|
||||
|
||||
if (extension.empty()) {
|
||||
// The GetPreferredExtensionForMimeType call will end up going to disk. Do
|
||||
// this on another thread to avoid slowing the IO thread.
|
||||
// http://crbug.com/61827
|
||||
base::ThreadRestrictions::ScopedAllowIO allow_io;
|
||||
net::GetPreferredExtensionForMimeType(mime_type, &extension);
|
||||
}
|
||||
|
||||
generated_extension->swap(extension);
|
||||
}
|
||||
|
||||
// Used to make sure we have a safe file extension and filename for a
|
||||
// download. |file_name| can either be just the file name or it can be a
|
||||
// full path to a file.
|
||||
// From chrome/browser/download/download_util.cc
|
||||
void GenerateSafeFileName(const std::string& mime_type, FilePath* file_name) {
|
||||
// Make sure we get the right file extension
|
||||
FilePath::StringType extension;
|
||||
GenerateExtension(*file_name, mime_type, &extension);
|
||||
*file_name = file_name->ReplaceExtension(extension);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Prepend "_" to the file name if it's a reserved name
|
||||
FilePath::StringType leaf_name = file_name->BaseName().value();
|
||||
DCHECK(!leaf_name.empty());
|
||||
if (IsReservedName(leaf_name)) {
|
||||
leaf_name = FilePath::StringType(FILE_PATH_LITERAL("_")) + leaf_name;
|
||||
*file_name = file_name->DirName();
|
||||
if (file_name->value() == FilePath::kCurrentDirectory) {
|
||||
*file_name = FilePath(leaf_name);
|
||||
} else {
|
||||
*file_name = file_name->Append(leaf_name);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Create a file name based on the response from the server.
|
||||
// From chrome/browser/download/download_util.cc
|
||||
void GenerateFileName(const GURL& url,
|
||||
const std::string& content_disposition,
|
||||
const std::string& referrer_charset,
|
||||
const std::string& mime_type,
|
||||
FilePath* generated_name) {
|
||||
string16 new_name = net::GetSuggestedFilename(GURL(url),
|
||||
content_disposition,
|
||||
referrer_charset,
|
||||
string16(L"download"));
|
||||
|
||||
// TODO(evan): this code is totally wrong -- we should just generate
|
||||
// Unicode filenames and do all this encoding switching at the end.
|
||||
// However, I'm just shuffling wrong code around, at least not adding
|
||||
// to it.
|
||||
#if defined(OS_WIN)
|
||||
*generated_name = FilePath(new_name);
|
||||
#else
|
||||
*generated_name = FilePath(
|
||||
base::SysWideToNativeMB(UTF16ToWide(new_name)));
|
||||
#endif
|
||||
|
||||
DCHECK(!generated_name->empty());
|
||||
|
||||
GenerateSafeFileName(mime_type, generated_name);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class DragDropThread : public base::Thread {
|
||||
public:
|
||||
explicit DragDropThread(BrowserDragDelegate* drag_handler)
|
||||
: base::Thread("Chrome_DragDropThread"),
|
||||
drag_handler_(drag_handler) {
|
||||
}
|
||||
|
||||
virtual ~DragDropThread() {
|
||||
Thread::Stop();
|
||||
}
|
||||
|
||||
protected:
|
||||
// base::Thread implementations:
|
||||
virtual void Init() {
|
||||
int ole_result = OleInitialize(NULL);
|
||||
DCHECK(ole_result == S_OK);
|
||||
}
|
||||
|
||||
virtual void CleanUp() {
|
||||
OleUninitialize();
|
||||
}
|
||||
|
||||
private:
|
||||
// Hold a reference count to BrowserDragDelegate to make sure that it is always
|
||||
// alive in the thread lifetime.
|
||||
scoped_refptr<BrowserDragDelegate> drag_handler_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(DragDropThread);
|
||||
};
|
||||
|
||||
BrowserDragDelegate::BrowserDragDelegate(BrowserWebViewDelegate* view)
|
||||
: drag_drop_thread_id_(0),
|
||||
view_(view),
|
||||
drag_ended_(false),
|
||||
old_drop_target_suspended_state_(false) {
|
||||
}
|
||||
|
||||
BrowserDragDelegate::~BrowserDragDelegate() {
|
||||
DCHECK(CefThread::CurrentlyOn(CefThread::UI));
|
||||
DCHECK(!drag_drop_thread_.get());
|
||||
}
|
||||
|
||||
void BrowserDragDelegate::StartDragging(const WebDropData& drop_data,
|
||||
WebDragOperationsMask ops,
|
||||
const SkBitmap& image,
|
||||
const gfx::Point& image_offset) {
|
||||
DCHECK(CefThread::CurrentlyOn(CefThread::UI));
|
||||
|
||||
CefBrowserImpl* browser = view_->GetBrowser();
|
||||
WebView* web_view = browser->UIT_GetWebView();
|
||||
drag_source_ = new WebDragSource(browser->UIT_GetWebViewWndHandle(),
|
||||
web_view);
|
||||
|
||||
const GURL& page_url = web_view->mainFrame()->url();
|
||||
const std::string& page_encoding = web_view->mainFrame()->encoding().utf8();
|
||||
|
||||
// If it is not drag-out, do the drag-and-drop in the current UI thread.
|
||||
if (drop_data.download_metadata.empty()) {
|
||||
DoDragging(drop_data, ops, page_url, page_encoding, image, image_offset);
|
||||
EndDragging(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// We do not want to drag and drop the download to itself.
|
||||
old_drop_target_suspended_state_ = view_->drop_target()->suspended();
|
||||
view_->drop_target()->set_suspended(true);
|
||||
|
||||
// Start a background thread to do the drag-and-drop.
|
||||
DCHECK(!drag_drop_thread_.get());
|
||||
drag_drop_thread_.reset(new DragDropThread(this));
|
||||
base::Thread::Options options;
|
||||
options.message_loop_type = MessageLoop::TYPE_UI;
|
||||
if (drag_drop_thread_->StartWithOptions(options)) {
|
||||
drag_drop_thread_->message_loop()->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableMethod(this,
|
||||
&BrowserDragDelegate::StartBackgroundDragging,
|
||||
drop_data,
|
||||
ops,
|
||||
page_url,
|
||||
page_encoding,
|
||||
image,
|
||||
image_offset));
|
||||
}
|
||||
|
||||
// Install a hook procedure to monitor the messages so that we can forward
|
||||
// the appropriate ones to the background thread.
|
||||
drag_out_thread_id = drag_drop_thread_->thread_id();
|
||||
mouse_up_received = false;
|
||||
DCHECK(!msg_hook);
|
||||
msg_hook = SetWindowsHookEx(WH_MSGFILTER,
|
||||
MsgFilterProc,
|
||||
NULL,
|
||||
GetCurrentThreadId());
|
||||
|
||||
// Attach the input state of the background thread to the UI thread so that
|
||||
// SetCursor can work from the background thread.
|
||||
AttachThreadInput(drag_out_thread_id, GetCurrentThreadId(), TRUE);
|
||||
}
|
||||
|
||||
void BrowserDragDelegate::StartBackgroundDragging(
|
||||
const WebDropData& drop_data,
|
||||
WebDragOperationsMask ops,
|
||||
const GURL& page_url,
|
||||
const std::string& page_encoding,
|
||||
const SkBitmap& image,
|
||||
const gfx::Point& image_offset) {
|
||||
drag_drop_thread_id_ = base::PlatformThread::CurrentId();
|
||||
|
||||
DoDragging(drop_data, ops, page_url, page_encoding, image, image_offset);
|
||||
CefThread::PostTask(
|
||||
CefThread::UI, FROM_HERE,
|
||||
NewRunnableMethod(this, &BrowserDragDelegate::EndDragging, true));
|
||||
}
|
||||
|
||||
void BrowserDragDelegate::PrepareDragForDownload(
|
||||
const WebDropData& drop_data,
|
||||
ui::OSExchangeData* data,
|
||||
const GURL& page_url,
|
||||
const std::string& page_encoding) {
|
||||
// Parse the download metadata.
|
||||
string16 mime_type;
|
||||
FilePath file_name;
|
||||
GURL download_url;
|
||||
if (!ParseDownloadMetadata(drop_data.download_metadata,
|
||||
&mime_type,
|
||||
&file_name,
|
||||
&download_url))
|
||||
return;
|
||||
|
||||
// Generate the download filename.
|
||||
std::string content_disposition =
|
||||
"attachment; filename=" + UTF16ToUTF8(file_name.value());
|
||||
FilePath generated_file_name;
|
||||
GenerateFileName(download_url,
|
||||
content_disposition,
|
||||
std::string(),
|
||||
UTF16ToUTF8(mime_type),
|
||||
&generated_file_name);
|
||||
|
||||
// Provide the data as file (CF_HDROP). A temporary download file with the
|
||||
// Zone.Identifier ADS (Alternate Data Stream) attached will be created.
|
||||
linked_ptr<net::FileStream> empty_file_stream;
|
||||
scoped_refptr<DragDownloadFile> download_file =
|
||||
new DragDownloadFile(generated_file_name,
|
||||
empty_file_stream,
|
||||
download_url,
|
||||
page_url,
|
||||
page_encoding,
|
||||
view_);
|
||||
ui::OSExchangeData::DownloadFileInfo file_download(FilePath(),
|
||||
download_file.get());
|
||||
data->SetDownloadFileInfo(file_download);
|
||||
|
||||
// Enable asynchronous operation.
|
||||
ui::OSExchangeDataProviderWin::GetIAsyncOperation(*data)->SetAsyncMode(TRUE);
|
||||
}
|
||||
|
||||
void BrowserDragDelegate::PrepareDragForFileContents(
|
||||
const WebDropData& drop_data, ui::OSExchangeData* data) {
|
||||
// Images without ALT text will only have a file extension so we need to
|
||||
// synthesize one from the provided extension and URL.
|
||||
FilePath file_name(drop_data.file_description_filename);
|
||||
file_name = file_name.BaseName().RemoveExtension();
|
||||
if (file_name.value().empty()) {
|
||||
// Retrieve the name from the URL.
|
||||
file_name = FilePath(
|
||||
net::GetSuggestedFilename(drop_data.url, "", "", string16()));
|
||||
if (file_name.value().size() + drop_data.file_extension.size() + 1 >
|
||||
MAX_PATH) {
|
||||
file_name = FilePath(file_name.value().substr(
|
||||
0, MAX_PATH - drop_data.file_extension.size() - 2));
|
||||
}
|
||||
}
|
||||
file_name = file_name.ReplaceExtension(drop_data.file_extension);
|
||||
data->SetFileContents(file_name.value(), drop_data.file_contents);
|
||||
}
|
||||
|
||||
void BrowserDragDelegate::PrepareDragForUrl(const WebDropData& drop_data,
|
||||
ui::OSExchangeData* data) {
|
||||
if (drop_data.url.SchemeIs("javascript")) {
|
||||
// We don't want to allow javascript URLs to be dragged to the desktop.
|
||||
} else {
|
||||
data->SetURL(drop_data.url, drop_data.url_title);
|
||||
}
|
||||
}
|
||||
|
||||
void BrowserDragDelegate::DoDragging(const WebDropData& drop_data,
|
||||
WebDragOperationsMask ops,
|
||||
const GURL& page_url,
|
||||
const std::string& page_encoding,
|
||||
const SkBitmap& image,
|
||||
const gfx::Point& image_offset) {
|
||||
ui::OSExchangeData data;
|
||||
|
||||
if (!drop_data.download_metadata.empty()) {
|
||||
PrepareDragForDownload(drop_data, &data, page_url, page_encoding);
|
||||
|
||||
// Set the observer.
|
||||
ui::OSExchangeDataProviderWin::GetDataObjectImpl(data)->set_observer(this);
|
||||
} else {
|
||||
// We set the file contents before the URL because the URL also sets file
|
||||
// contents (to a .URL shortcut). We want to prefer file content data over
|
||||
// a shortcut so we add it first.
|
||||
if (!drop_data.file_contents.empty())
|
||||
PrepareDragForFileContents(drop_data, &data);
|
||||
if (!drop_data.text_html.empty())
|
||||
data.SetHtml(drop_data.text_html, drop_data.html_base_url);
|
||||
// We set the text contents before the URL because the URL also sets text
|
||||
// content.
|
||||
if (!drop_data.plain_text.empty())
|
||||
data.SetString(drop_data.plain_text);
|
||||
if (drop_data.url.is_valid())
|
||||
PrepareDragForUrl(drop_data, &data);
|
||||
}
|
||||
|
||||
// Set drag image.
|
||||
if (!image.isNull()) {
|
||||
drag_utils::SetDragImageOnDataObject(
|
||||
image, gfx::Size(image.width(), image.height()), image_offset, &data);
|
||||
}
|
||||
|
||||
// We need to enable recursive tasks on the message loop so we can get
|
||||
// updates while in the system DoDragDrop loop.
|
||||
bool old_state = MessageLoop::current()->NestableTasksAllowed();
|
||||
MessageLoop::current()->SetNestableTasksAllowed(true);
|
||||
DWORD effect;
|
||||
DoDragDrop(ui::OSExchangeDataProviderWin::GetIDataObject(data), drag_source_,
|
||||
web_drag_utils_win::WebDragOpMaskToWinDragOpMask(ops), &effect);
|
||||
MessageLoop::current()->SetNestableTasksAllowed(old_state);
|
||||
|
||||
// This works because WebDragSource::OnDragSourceDrop uses PostTask to
|
||||
// dispatch the actual event.
|
||||
drag_source_->set_effect(effect);
|
||||
}
|
||||
|
||||
void BrowserDragDelegate::EndDragging(bool restore_suspended_state) {
|
||||
DCHECK(CefThread::CurrentlyOn(CefThread::UI));
|
||||
|
||||
if (drag_ended_)
|
||||
return;
|
||||
drag_ended_ = true;
|
||||
|
||||
if (restore_suspended_state)
|
||||
view_->drop_target()->set_suspended(old_drop_target_suspended_state_);
|
||||
|
||||
if (msg_hook) {
|
||||
AttachThreadInput(drag_out_thread_id, GetCurrentThreadId(), FALSE);
|
||||
UnhookWindowsHookEx(msg_hook);
|
||||
msg_hook = NULL;
|
||||
}
|
||||
|
||||
view_->EndDragging();
|
||||
}
|
||||
|
||||
void BrowserDragDelegate::CancelDrag() {
|
||||
DCHECK(CefThread::CurrentlyOn(CefThread::UI));
|
||||
|
||||
drag_source_->CancelDrag();
|
||||
}
|
||||
|
||||
void BrowserDragDelegate::CloseThread() {
|
||||
DCHECK(CefThread::CurrentlyOn(CefThread::UI));
|
||||
|
||||
drag_drop_thread_.reset();
|
||||
}
|
||||
|
||||
void BrowserDragDelegate::OnWaitForData() {
|
||||
DCHECK(drag_drop_thread_id_ == base::PlatformThread::CurrentId());
|
||||
|
||||
// When the left button is released and we start to wait for the data, end
|
||||
// the dragging before DoDragDrop returns. This makes the page leave the drag
|
||||
// mode so that it can start to process the normal input events.
|
||||
CefThread::PostTask(
|
||||
CefThread::UI, FROM_HERE,
|
||||
NewRunnableMethod(this, &BrowserDragDelegate::EndDragging, true));
|
||||
}
|
||||
|
||||
void BrowserDragDelegate::OnDataObjectDisposed() {
|
||||
DCHECK(drag_drop_thread_id_ == base::PlatformThread::CurrentId());
|
||||
|
||||
// The drag-and-drop thread is only closed after OLE is done with
|
||||
// DataObjectImpl.
|
||||
CefThread::PostTask(
|
||||
CefThread::UI, FROM_HERE,
|
||||
NewRunnableMethod(this, &BrowserDragDelegate::CloseThread));
|
||||
}
|
102
libcef/browser_drag_delegate_win.h
Normal file
102
libcef/browser_drag_delegate_win.h
Normal file
@ -0,0 +1,102 @@
|
||||
// Copyright (c) 2011 The Chromium Embedded Framework Authors.
|
||||
// Portions copyright (c) 2009 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 _BROWSER_DRAG_DELEGATE_WIN_H
|
||||
#define _BROWSER_DRAG_DELEGATE_WIN_H
|
||||
#pragma once
|
||||
|
||||
#include "base/ref_counted.h"
|
||||
#include "base/scoped_ptr.h"
|
||||
#include "base/threading/platform_thread.h"
|
||||
#include "third_party/skia/include/core/SkBitmap.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDragOperation.h"
|
||||
#include "ui/base/dragdrop/os_exchange_data_provider_win.h"
|
||||
#include "ui/gfx/point.h"
|
||||
|
||||
class BrowserWebViewDelegate;
|
||||
class DragDropThread;
|
||||
class WebDragSource;
|
||||
struct WebDropData;
|
||||
|
||||
// Windows-specific drag-and-drop handling.
|
||||
// If we are dragging a virtual file out of the browser, we use a background
|
||||
// thread to do the drag-and-drop because we do not want to run nested
|
||||
// message loop in the UI thread. For all other cases, the drag-and-drop happens
|
||||
// in the UI thread.
|
||||
class BrowserDragDelegate
|
||||
: public ui::DataObjectImpl::Observer,
|
||||
public base::RefCountedThreadSafe<BrowserDragDelegate> {
|
||||
public:
|
||||
explicit BrowserDragDelegate(BrowserWebViewDelegate* view);
|
||||
virtual ~BrowserDragDelegate();
|
||||
|
||||
// Called on UI thread.
|
||||
void StartDragging(const WebDropData& drop_data,
|
||||
WebKit::WebDragOperationsMask ops,
|
||||
const SkBitmap& image,
|
||||
const gfx::Point& image_offset);
|
||||
void CancelDrag();
|
||||
|
||||
// DataObjectImpl::Observer implementation.
|
||||
// Called on drag-and-drop thread.
|
||||
virtual void OnWaitForData();
|
||||
virtual void OnDataObjectDisposed();
|
||||
|
||||
private:
|
||||
// Called on either UI thread or drag-and-drop thread.
|
||||
void PrepareDragForDownload(const WebDropData& drop_data,
|
||||
ui::OSExchangeData* data,
|
||||
const GURL& page_url,
|
||||
const std::string& page_encoding);
|
||||
void PrepareDragForFileContents(const WebDropData& drop_data,
|
||||
ui::OSExchangeData* data);
|
||||
void PrepareDragForUrl(const WebDropData& drop_data,
|
||||
ui::OSExchangeData* data);
|
||||
void DoDragging(const WebDropData& drop_data,
|
||||
WebKit::WebDragOperationsMask ops,
|
||||
const GURL& page_url,
|
||||
const std::string& page_encoding,
|
||||
const SkBitmap& image,
|
||||
const gfx::Point& image_offset);
|
||||
|
||||
// Called on drag-and-drop thread.
|
||||
void StartBackgroundDragging(const WebDropData& drop_data,
|
||||
WebKit::WebDragOperationsMask ops,
|
||||
const GURL& page_url,
|
||||
const std::string& page_encoding,
|
||||
const SkBitmap& image,
|
||||
const gfx::Point& image_offset);
|
||||
// Called on UI thread.
|
||||
void EndDragging(bool restore_suspended_state);
|
||||
void CloseThread();
|
||||
|
||||
// For debug check only. Access only on drag-and-drop thread.
|
||||
base::PlatformThreadId drag_drop_thread_id_;
|
||||
|
||||
// All the member variables below are accessed on UI thread.
|
||||
|
||||
// Keep track of the BrowserWebViewDelegate it is associated with.
|
||||
BrowserWebViewDelegate* view_;
|
||||
|
||||
// |drag_source_| is our callback interface passed to the system when we
|
||||
// want to initiate a drag and drop operation. We use it to tell if a
|
||||
// drag operation is happening.
|
||||
scoped_refptr<WebDragSource> drag_source_;
|
||||
|
||||
// The thread used by the drag-out download. This is because we want to avoid
|
||||
// running nested message loop in main UI thread.
|
||||
scoped_ptr<DragDropThread> drag_drop_thread_;
|
||||
|
||||
// The flag to guard that EndDragging is not called twice.
|
||||
bool drag_ended_;
|
||||
|
||||
// Keep track of the old suspended state of the drop target.
|
||||
bool old_drop_target_suspended_state_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(BrowserDragDelegate);
|
||||
};
|
||||
|
||||
|
||||
#endif // _BROWSER_DRAG_DELEGATE_WIN_H
|
@ -1,72 +0,0 @@
|
||||
// Copyright (c) 2010 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 "browser_drop_delegate.h"
|
||||
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDragData.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebPoint.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
|
||||
#include "webkit/glue/webdropdata.h"
|
||||
|
||||
using WebKit::WebDragOperation;
|
||||
using WebKit::WebDragOperationCopy;
|
||||
using WebKit::WebPoint;
|
||||
using WebKit::WebView;
|
||||
|
||||
BrowserDropDelegate::BrowserDropDelegate(HWND source_hwnd, WebKit::WebView* webview)
|
||||
: ui::DropTarget(source_hwnd),
|
||||
webview_(webview) {
|
||||
}
|
||||
|
||||
DWORD BrowserDropDelegate::OnDragEnter(IDataObject* data_object,
|
||||
DWORD key_state,
|
||||
POINT cursor_position,
|
||||
DWORD effect) {
|
||||
WebDropData drop_data;
|
||||
WebDropData::PopulateWebDropData(data_object, &drop_data);
|
||||
|
||||
POINT client_pt = cursor_position;
|
||||
ScreenToClient(GetHWND(), &client_pt);
|
||||
WebDragOperation op = webview_->dragTargetDragEnter(
|
||||
drop_data.ToDragData(), drop_data.identity,
|
||||
WebPoint(client_pt.x, client_pt.y),
|
||||
WebPoint(cursor_position.x, cursor_position.y),
|
||||
WebDragOperationCopy);
|
||||
// TODO(snej): Pass the real drag operation instead
|
||||
return op ? DROPEFFECT_COPY : DROPEFFECT_NONE;
|
||||
// TODO(snej): Return the real drop effect constant matching 'op'
|
||||
}
|
||||
|
||||
DWORD BrowserDropDelegate::OnDragOver(IDataObject* data_object,
|
||||
DWORD key_state,
|
||||
POINT cursor_position,
|
||||
DWORD effect) {
|
||||
POINT client_pt = cursor_position;
|
||||
ScreenToClient(GetHWND(), &client_pt);
|
||||
WebDragOperation op = webview_->dragTargetDragOver(
|
||||
WebPoint(client_pt.x, client_pt.y),
|
||||
WebPoint(cursor_position.x, cursor_position.y),
|
||||
WebDragOperationCopy);
|
||||
// TODO(snej): Pass the real drag operation instead
|
||||
return op ? DROPEFFECT_COPY : DROPEFFECT_NONE;
|
||||
// TODO(snej): Return the real drop effect constant matching 'op'
|
||||
}
|
||||
|
||||
void BrowserDropDelegate::OnDragLeave(IDataObject* data_object) {
|
||||
webview_->dragTargetDragLeave();
|
||||
}
|
||||
|
||||
DWORD BrowserDropDelegate::OnDrop(IDataObject* data_object,
|
||||
DWORD key_state,
|
||||
POINT cursor_position,
|
||||
DWORD effect) {
|
||||
POINT client_pt = cursor_position;
|
||||
ScreenToClient(GetHWND(), &client_pt);
|
||||
webview_->dragTargetDrop(
|
||||
WebPoint(client_pt.x, client_pt.y),
|
||||
WebPoint(cursor_position.x, cursor_position.y));
|
||||
|
||||
// webkit win port always returns DROPEFFECT_NONE
|
||||
return DROPEFFECT_NONE;
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
// Copyright (c) 2010 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.
|
||||
//
|
||||
// A class that implements BaseDropTarget for the test shell webview delegate.
|
||||
|
||||
#ifndef _BROWSER_DROP_DELEGATE_H
|
||||
#define _BROWSER_DROP_DELEGATE_H
|
||||
|
||||
#include "ui/base/dragdrop/drop_target.h"
|
||||
|
||||
namespace WebKit {
|
||||
class WebView;
|
||||
}
|
||||
|
||||
class BrowserDropDelegate : public ui::DropTarget {
|
||||
public:
|
||||
BrowserDropDelegate(HWND source_hwnd, WebKit::WebView* webview);
|
||||
|
||||
protected:
|
||||
// BaseDropTarget methods
|
||||
virtual DWORD OnDragEnter(IDataObject* data_object,
|
||||
DWORD key_state,
|
||||
POINT cursor_position,
|
||||
DWORD effect);
|
||||
virtual DWORD OnDragOver(IDataObject* data_object,
|
||||
DWORD key_state,
|
||||
POINT cursor_position,
|
||||
DWORD effect);
|
||||
virtual void OnDragLeave(IDataObject* data_object);
|
||||
virtual DWORD OnDrop(IDataObject* data_object,
|
||||
DWORD key_state,
|
||||
POINT cursor_position,
|
||||
DWORD effect);
|
||||
|
||||
private:
|
||||
WebKit::WebView* webview_;
|
||||
};
|
||||
|
||||
#endif // _BROWSER_DROP_DELEGATE_H
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFileSystemCallbacks.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebHistoryItem.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebImage.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebKit.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebKitClient.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebNode.h"
|
||||
@ -71,8 +72,8 @@
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// TODO(port): make these files work everywhere.
|
||||
#include "browser_drag_delegate.h"
|
||||
#include "browser_drop_delegate.h"
|
||||
#include "browser_drag_delegate_win.h"
|
||||
#include "web_drop_target_win.h"
|
||||
#endif
|
||||
|
||||
using appcache::WebApplicationCacheHostImpl;
|
||||
@ -423,19 +424,14 @@ void BrowserWebViewDelegate::startDragging(
|
||||
WebDragOperationsMask mask,
|
||||
const WebImage& image,
|
||||
const WebPoint& image_offset) {
|
||||
// TODO(tc): Drag and drop is disabled in the test shell because we need
|
||||
// to be able to convert from WebDragData to an IDataObject.
|
||||
//if (!drag_delegate_)
|
||||
// drag_delegate_ = new BrowserDragDelegate(shell_->webViewWnd(),
|
||||
// shell_->webView());
|
||||
//const DWORD ok_effect = DROPEFFECT_COPY | DROPEFFECT_LINK | DROPEFFECT_MOVE;
|
||||
//DWORD effect;
|
||||
//HRESULT res = DoDragDrop(drop_data.data_object, drag_delegate_.get(),
|
||||
// ok_effect, &effect);
|
||||
//DCHECK(DRAGDROP_S_DROP == res || DRAGDROP_S_CANCEL == res);
|
||||
WebView* view = browser_->UIT_GetWebView();
|
||||
if (view)
|
||||
view->dragSourceSystemDragEnded();
|
||||
#if defined(OS_WIN)
|
||||
drag_delegate_ = new BrowserDragDelegate(this);
|
||||
drag_delegate_->StartDragging(WebDropData(data), mask, image.getSkBitmap(),
|
||||
image_offset);
|
||||
#else
|
||||
// TODO(port): Support drag and drop.
|
||||
EndDragging();
|
||||
#endif
|
||||
}
|
||||
|
||||
void BrowserWebViewDelegate::focusNext() {
|
||||
@ -901,15 +897,15 @@ void BrowserWebViewDelegate::SetSelectTrailingWhitespaceEnabled(bool enabled) {
|
||||
void BrowserWebViewDelegate::RegisterDragDrop() {
|
||||
#if defined(OS_WIN)
|
||||
// TODO(port): add me once drag and drop works.
|
||||
DCHECK(!drop_delegate_);
|
||||
drop_delegate_ = new BrowserDropDelegate(browser_->UIT_GetWebViewWndHandle(),
|
||||
browser_->UIT_GetWebView());
|
||||
DCHECK(!drop_target_);
|
||||
drop_target_ = new WebDropTarget(browser_->UIT_GetWebViewWndHandle(),
|
||||
browser_->UIT_GetWebView());
|
||||
#endif
|
||||
}
|
||||
|
||||
void BrowserWebViewDelegate::RevokeDragDrop() {
|
||||
#if defined(OS_WIN)
|
||||
if (drop_delegate_.get())
|
||||
if (drop_target_.get())
|
||||
::RevokeDragDrop(browser_->UIT_GetWebViewWndHandle());
|
||||
#endif
|
||||
}
|
||||
@ -975,6 +971,13 @@ WebWidgetHost* BrowserWebViewDelegate::GetWidgetHost() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void BrowserWebViewDelegate::EndDragging() {
|
||||
browser_->UIT_GetWebView()->dragSourceSystemDragEnded();
|
||||
#if defined(OS_WIN)
|
||||
drag_delegate_ = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void BrowserWebViewDelegate::UpdateForCommittedLoad(WebFrame* frame,
|
||||
bool is_new_navigation) {
|
||||
// Code duplicated from RenderView::DidCommitLoadForFrame.
|
||||
|
@ -32,8 +32,8 @@
|
||||
#endif
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "browser_drag_delegate.h"
|
||||
#include "browser_drop_delegate.h"
|
||||
class BrowserDragDelegate;
|
||||
class WebDropTarget;
|
||||
#endif
|
||||
|
||||
#if defined(TOOLKIT_USES_GTK)
|
||||
@ -211,8 +211,8 @@ class BrowserWebViewDelegate : public WebKit::WebViewClient,
|
||||
// Additional accessors
|
||||
WebKit::WebFrame* top_loading_frame() { return top_loading_frame_; }
|
||||
#if defined(OS_WIN)
|
||||
IDropTarget* drop_delegate() { return drop_delegate_.get(); }
|
||||
IDropSource* drag_delegate() { return drag_delegate_.get(); }
|
||||
BrowserDragDelegate* drag_delegate() { return drag_delegate_.get(); }
|
||||
WebDropTarget* drop_target() { return drop_target_.get(); }
|
||||
#endif
|
||||
|
||||
void set_pending_extra_data(BrowserExtraData* extra_data) {
|
||||
@ -251,6 +251,9 @@ class BrowserWebViewDelegate : public WebKit::WebViewClient,
|
||||
void SetPopupMenuInfo(const WebKit::WebPopupMenuInfo& info);
|
||||
#endif
|
||||
|
||||
// Called after dragging has finished.
|
||||
void EndDragging();
|
||||
|
||||
protected:
|
||||
// Default handling of JavaScript messages.
|
||||
void ShowJavaScriptAlert(WebKit::WebFrame* webframe,
|
||||
@ -314,7 +317,7 @@ class BrowserWebViewDelegate : public WebKit::WebViewClient,
|
||||
#if defined(OS_WIN)
|
||||
// Classes needed by drag and drop.
|
||||
scoped_refptr<BrowserDragDelegate> drag_delegate_;
|
||||
scoped_refptr<BrowserDropDelegate> drop_delegate_;
|
||||
scoped_refptr<WebDropTarget> drop_target_;
|
||||
#endif
|
||||
|
||||
#if defined(OS_LINUX)
|
||||
|
@ -8,8 +8,6 @@
|
||||
// have initialized a MessageLoop before these methods are called.
|
||||
|
||||
#include "browser_webview_delegate.h"
|
||||
#include "browser_drag_delegate.h"
|
||||
#include "browser_drop_delegate.h"
|
||||
#include "browser_navigation_controller.h"
|
||||
#include "browser_impl.h"
|
||||
#include "cef_context.h"
|
||||
|
@ -233,7 +233,8 @@ bool CefCreateURL(const CefURLParts& parts,
|
||||
|
||||
// CefContext
|
||||
|
||||
CefContext::CefContext() : initialized_(false), shutting_down_(false)
|
||||
CefContext::CefContext()
|
||||
: initialized_(false), shutting_down_(false), current_webviewhost_(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
class BrowserRequestContext;
|
||||
class CefBrowserImpl;
|
||||
class WebViewHost;
|
||||
|
||||
class CefContext : public CefThreadSafeBase<CefBase>
|
||||
{
|
||||
@ -65,6 +66,13 @@ public:
|
||||
{ storage_context_.reset(storage_context); }
|
||||
DOMStorageContext* storage_context() { return storage_context_.get(); }
|
||||
|
||||
// Used to keep track of the web view host we're dragging over. WARNING:
|
||||
// this pointer should never be dereferenced. Use it only for comparing
|
||||
// pointers.
|
||||
WebViewHost* current_webviewhost() { return current_webviewhost_; }
|
||||
void set_current_webviewhost(WebViewHost* host)
|
||||
{ current_webviewhost_ = host; }
|
||||
|
||||
static bool ImplementsThreadSafeReferenceCounting() { return true; }
|
||||
|
||||
private:
|
||||
@ -94,6 +102,8 @@ private:
|
||||
|
||||
// Used for assigning unique IDs to browser instances.
|
||||
int next_browser_id_;
|
||||
|
||||
WebViewHost* current_webviewhost_;
|
||||
};
|
||||
|
||||
// Global context object pointer.
|
||||
|
161
libcef/drag_download_file.cc
Normal file
161
libcef/drag_download_file.cc
Normal file
@ -0,0 +1,161 @@
|
||||
// Copyright (c) 2011 The Chromium Embedded Framework Authors.
|
||||
// Portions copyright (c) 2009-2010 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 "drag_download_file.h"
|
||||
#include "browser_impl.h"
|
||||
#include "cef_thread.h"
|
||||
|
||||
#include "base/file_util.h"
|
||||
#include "base/message_loop.h"
|
||||
#include "net/base/file_stream.h"
|
||||
|
||||
DragDownloadFile::DragDownloadFile(
|
||||
const FilePath& file_name_or_path,
|
||||
linked_ptr<net::FileStream> file_stream,
|
||||
const GURL& url,
|
||||
const GURL& referrer,
|
||||
const std::string& referrer_encoding,
|
||||
BrowserWebViewDelegate* view)
|
||||
: file_stream_(file_stream),
|
||||
url_(url),
|
||||
referrer_(referrer),
|
||||
referrer_encoding_(referrer_encoding),
|
||||
view_(view),
|
||||
drag_message_loop_(MessageLoop::current()),
|
||||
is_started_(false),
|
||||
is_successful_(false) {
|
||||
#if defined(OS_WIN)
|
||||
DCHECK(!file_name_or_path.empty() && !file_stream.get());
|
||||
file_name_ = file_name_or_path;
|
||||
#elif defined(OS_POSIX)
|
||||
DCHECK(!file_name_or_path.empty() && file_stream.get());
|
||||
file_path_ = file_name_or_path;
|
||||
#endif
|
||||
}
|
||||
|
||||
DragDownloadFile::~DragDownloadFile() {
|
||||
AssertCurrentlyOnDragThread();
|
||||
|
||||
// Since the target application can still hold and use the dragged file,
|
||||
// we do not know the time that it can be safely deleted. To solve this
|
||||
// problem, we schedule it to be removed after the system is restarted.
|
||||
#if defined(OS_WIN)
|
||||
if (!temp_dir_path_.empty()) {
|
||||
if (!file_path_.empty())
|
||||
file_util::DeleteAfterReboot(file_path_);
|
||||
file_util::DeleteAfterReboot(temp_dir_path_);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool DragDownloadFile::Start(ui::DownloadFileObserver* observer) {
|
||||
AssertCurrentlyOnDragThread();
|
||||
|
||||
if (is_started_)
|
||||
return true;
|
||||
is_started_ = true;
|
||||
|
||||
DCHECK(!observer_.get());
|
||||
observer_ = observer;
|
||||
|
||||
if (!file_stream_.get()) {
|
||||
// Create a temporary directory to save the temporary download file. We do
|
||||
// not want to use the default download directory since we do not want the
|
||||
// twisted file name shown in the download shelf if the file with the same
|
||||
// name already exists.
|
||||
if (!file_util::CreateNewTempDirectory(FILE_PATH_LITERAL("chrome"),
|
||||
&temp_dir_path_))
|
||||
return false;
|
||||
|
||||
file_path_ = temp_dir_path_.Append(file_name_);
|
||||
}
|
||||
|
||||
InitiateDownload();
|
||||
|
||||
// On Windows, we need to wait till the download file is completed.
|
||||
#if defined(OS_WIN)
|
||||
StartNestedMessageLoop();
|
||||
#endif
|
||||
|
||||
return is_successful_;
|
||||
}
|
||||
|
||||
void DragDownloadFile::Stop() {
|
||||
}
|
||||
|
||||
void DragDownloadFile::InitiateDownload() {
|
||||
#if defined(OS_WIN)
|
||||
// DownloadManager could only be invoked from the UI thread.
|
||||
if (!CefThread::CurrentlyOn(CefThread::UI)) {
|
||||
CefThread::PostTask(
|
||||
CefThread::UI, FROM_HERE,
|
||||
NewRunnableMethod(this,
|
||||
&DragDownloadFile::InitiateDownload));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// TODO: You seem to have found an example of HTML5 drag and drop download.
|
||||
// Please report it to the CEF developers so that we can add support for it.
|
||||
NOTREACHED();
|
||||
bool is_successful = false;
|
||||
DownloadCompleted(is_successful);
|
||||
}
|
||||
|
||||
void DragDownloadFile::DownloadCompleted(bool is_successful) {
|
||||
#if defined(OS_WIN)
|
||||
// If not in drag-and-drop thread, defer the running to it.
|
||||
if (drag_message_loop_ != MessageLoop::current()) {
|
||||
drag_message_loop_->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableMethod(this,
|
||||
&DragDownloadFile::DownloadCompleted,
|
||||
is_successful));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
is_successful_ = is_successful;
|
||||
|
||||
// On Windows, we need to stop the waiting.
|
||||
#if defined(OS_WIN)
|
||||
QuitNestedMessageLoop();
|
||||
#endif
|
||||
}
|
||||
|
||||
void DragDownloadFile::AssertCurrentlyOnDragThread() {
|
||||
// Only do the check on Windows where two threads are involved.
|
||||
#if defined(OS_WIN)
|
||||
DCHECK(drag_message_loop_ == MessageLoop::current());
|
||||
#endif
|
||||
}
|
||||
|
||||
void DragDownloadFile::AssertCurrentlyOnUIThread() {
|
||||
// Only do the check on Windows where two threads are involved.
|
||||
#if defined(OS_WIN)
|
||||
DCHECK(CefThread::CurrentlyOn(CefThread::UI));
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(OS_WIN)
|
||||
void DragDownloadFile::StartNestedMessageLoop() {
|
||||
AssertCurrentlyOnDragThread();
|
||||
|
||||
bool old_state = MessageLoop::current()->NestableTasksAllowed();
|
||||
MessageLoop::current()->SetNestableTasksAllowed(true);
|
||||
is_running_nested_message_loop_ = true;
|
||||
MessageLoop::current()->Run();
|
||||
MessageLoop::current()->SetNestableTasksAllowed(old_state);
|
||||
}
|
||||
|
||||
void DragDownloadFile::QuitNestedMessageLoop() {
|
||||
AssertCurrentlyOnDragThread();
|
||||
|
||||
if (is_running_nested_message_loop_) {
|
||||
is_running_nested_message_loop_ = false;
|
||||
MessageLoop::current()->Quit();
|
||||
}
|
||||
}
|
||||
#endif
|
96
libcef/drag_download_file.h
Normal file
96
libcef/drag_download_file.h
Normal file
@ -0,0 +1,96 @@
|
||||
// Copyright (c) 2011 The Chromium Embedded Framework Authors.
|
||||
// Portions copyright (c) 2009-2010 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 _DRAG_DOWNLOAD_FILE_H
|
||||
#define _DRAG_DOWNLOAD_FILE_H
|
||||
#pragma once
|
||||
|
||||
#include "base/file_path.h"
|
||||
#include "base/linked_ptr.h"
|
||||
#include "base/message_loop.h"
|
||||
#include "googleurl/src/gurl.h"
|
||||
#include "ui/base/dragdrop/download_file_interface.h"
|
||||
|
||||
class BrowserWebViewDelegate;
|
||||
|
||||
namespace net {
|
||||
class FileStream;
|
||||
}
|
||||
|
||||
class DragDownloadFile : public ui::DownloadFileProvider {
|
||||
public:
|
||||
// On Windows, we need to download into a temporary file. Two threads are
|
||||
// involved: background drag-and-drop thread and UI thread.
|
||||
// The first parameter file_name_or_path should contain file name while the
|
||||
// second parameter file_stream should be NULL.
|
||||
//
|
||||
// On MacOSX, we need to download into a file stream that has already been
|
||||
// created. Only UI thread is involved.
|
||||
// The file path and file stream should be provided as the first two
|
||||
// parameters.
|
||||
DragDownloadFile(const FilePath& file_name_or_path,
|
||||
linked_ptr<net::FileStream> file_stream,
|
||||
const GURL& url,
|
||||
const GURL& referrer,
|
||||
const std::string& referrer_encoding,
|
||||
BrowserWebViewDelegate* view);
|
||||
|
||||
// DownloadFileProvider methods.
|
||||
// Called on drag-and-drop thread (Windows).
|
||||
// Called on UI thread (MacOSX).
|
||||
virtual bool Start(ui::DownloadFileObserver* observer);
|
||||
virtual void Stop();
|
||||
#if defined(OS_WIN)
|
||||
virtual IStream* GetStream() { return NULL; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
// Called on drag-and-drop thread (Windows).
|
||||
// Called on UI thread (Windows).
|
||||
virtual ~DragDownloadFile();
|
||||
|
||||
// Called on drag-and-drop thread (Windows only).
|
||||
#if defined(OS_WIN)
|
||||
void StartNestedMessageLoop();
|
||||
void QuitNestedMessageLoop();
|
||||
#endif
|
||||
|
||||
// Called on either drag-and-drop thread or UI thread (Windows).
|
||||
// Called on UI thread (MacOSX).
|
||||
void InitiateDownload();
|
||||
void DownloadCompleted(bool is_successful);
|
||||
|
||||
// Helper methods to make sure we're in the correct thread.
|
||||
void AssertCurrentlyOnDragThread();
|
||||
void AssertCurrentlyOnUIThread();
|
||||
|
||||
// Initialized on drag-and-drop thread. Accessed on either thread after that
|
||||
// (Windows).
|
||||
// Accessed on UI thread (MacOSX).
|
||||
FilePath file_path_;
|
||||
FilePath file_name_;
|
||||
linked_ptr<net::FileStream> file_stream_;
|
||||
GURL url_;
|
||||
GURL referrer_;
|
||||
std::string referrer_encoding_;
|
||||
BrowserWebViewDelegate* view_;
|
||||
MessageLoop* drag_message_loop_;
|
||||
FilePath temp_dir_path_;
|
||||
|
||||
// Accessed on drag-and-drop thread (Windows).
|
||||
// Accessed on UI thread (MacOSX).
|
||||
bool is_started_;
|
||||
bool is_successful_;
|
||||
scoped_refptr<ui::DownloadFileObserver> observer_;
|
||||
|
||||
// Accessed on drag-and-drop thread (Windows only).
|
||||
#if defined(OS_WIN)
|
||||
bool is_running_nested_message_loop_;
|
||||
#endif
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(DragDownloadFile);
|
||||
};
|
||||
|
||||
#endif // _DRAG_DOWNLOAD_FILE_H
|
100
libcef/web_drag_source_win.cc
Normal file
100
libcef/web_drag_source_win.cc
Normal file
@ -0,0 +1,100 @@
|
||||
// Copyright (c) 2011 The Chromium Embedded Framework Authors.
|
||||
// Portions copyright (c) 2010 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 "web_drag_source_win.h"
|
||||
#include "web_drag_utils_win.h"
|
||||
#include "cef_thread.h"
|
||||
|
||||
#include "base/task.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebPoint.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
|
||||
|
||||
using WebKit::WebDragOperationNone;
|
||||
using WebKit::WebPoint;
|
||||
using WebKit::WebView;
|
||||
|
||||
namespace {
|
||||
|
||||
static void GetCursorPositions(gfx::NativeWindow wnd, gfx::Point* client,
|
||||
gfx::Point* screen) {
|
||||
POINT cursor_pos;
|
||||
GetCursorPos(&cursor_pos);
|
||||
screen->SetPoint(cursor_pos.x, cursor_pos.y);
|
||||
ScreenToClient(wnd, &cursor_pos);
|
||||
client->SetPoint(cursor_pos.x, cursor_pos.y);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// WebDragSource, public:
|
||||
|
||||
WebDragSource::WebDragSource(gfx::NativeWindow source_wnd, WebView* view)
|
||||
: ui::DragSource(),
|
||||
source_wnd_(source_wnd),
|
||||
view_(view),
|
||||
effect_(DROPEFFECT_NONE) {
|
||||
}
|
||||
|
||||
WebDragSource::~WebDragSource() {
|
||||
}
|
||||
|
||||
void WebDragSource::OnDragSourceCancel() {
|
||||
// Delegate to the UI thread if we do drag-and-drop in the background thread.
|
||||
if (!CefThread::CurrentlyOn(CefThread::UI)) {
|
||||
CefThread::PostTask(
|
||||
CefThread::UI, FROM_HERE,
|
||||
NewRunnableMethod(this, &WebDragSource::OnDragSourceCancel));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!view_)
|
||||
return;
|
||||
|
||||
gfx::Point client;
|
||||
gfx::Point screen;
|
||||
GetCursorPositions(source_wnd_, &client, &screen);
|
||||
view_->dragSourceEndedAt(client, screen, WebDragOperationNone);
|
||||
}
|
||||
|
||||
void WebDragSource::OnDragSourceDrop() {
|
||||
// On Windows, we check for drag end in IDropSource::QueryContinueDrag which
|
||||
// happens before IDropTarget::Drop is called. HTML5 requires the "dragend"
|
||||
// event to happen after the "drop" event. Since Windows calls these two
|
||||
// directly after each other we can just post a task to handle the
|
||||
// OnDragSourceDrop after the current task.
|
||||
CefThread::PostTask(
|
||||
CefThread::UI, FROM_HERE,
|
||||
NewRunnableMethod(this, &WebDragSource::DelayedOnDragSourceDrop));
|
||||
}
|
||||
|
||||
void WebDragSource::DelayedOnDragSourceDrop() {
|
||||
if (!view_)
|
||||
return;
|
||||
|
||||
gfx::Point client;
|
||||
gfx::Point screen;
|
||||
GetCursorPositions(source_wnd_, &client, &screen);
|
||||
view_->dragSourceEndedAt(client, screen,
|
||||
web_drag_utils_win::WinDragOpToWebDragOp(effect_));
|
||||
}
|
||||
|
||||
void WebDragSource::OnDragSourceMove() {
|
||||
// Delegate to the UI thread if we do drag-and-drop in the background thread.
|
||||
if (!CefThread::CurrentlyOn(CefThread::UI)) {
|
||||
CefThread::PostTask(
|
||||
CefThread::UI, FROM_HERE,
|
||||
NewRunnableMethod(this, &WebDragSource::OnDragSourceMove));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!view_)
|
||||
return;
|
||||
|
||||
gfx::Point client;
|
||||
gfx::Point screen;
|
||||
GetCursorPositions(source_wnd_, &client, &screen);
|
||||
view_->dragSourceMovedTo(client, screen, WebDragOperationNone);
|
||||
}
|
58
libcef/web_drag_source_win.h
Normal file
58
libcef/web_drag_source_win.h
Normal file
@ -0,0 +1,58 @@
|
||||
// Copyright (c) 2011 The Chromium Embedded Framework Authors.
|
||||
// Portions copyright (c) 2010 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 _WEB_DRAG_SOURCE_WIN_H
|
||||
#define _WEB_DRAG_SOURCE_WIN_H
|
||||
#pragma once
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "ui/base/dragdrop/drag_source.h"
|
||||
#include "ui/gfx/native_widget_types.h"
|
||||
#include "ui/gfx/point.h"
|
||||
|
||||
namespace WebKit {
|
||||
class WebView;
|
||||
};
|
||||
|
||||
// An IDropSource implementation for a WebView. Handles notifications sent
|
||||
// by an active drag-drop operation as the user mouses over other drop targets
|
||||
// on their system. This object tells Windows whether or not the drag should
|
||||
// continue, and supplies the appropriate cursors.
|
||||
class WebDragSource : public ui::DragSource {
|
||||
public:
|
||||
// Create a new DragSource for a given HWND and WebView.
|
||||
WebDragSource(gfx::NativeWindow source_wnd, WebKit::WebView* view);
|
||||
virtual ~WebDragSource();
|
||||
|
||||
void set_effect(DWORD effect) { effect_ = effect; }
|
||||
|
||||
protected:
|
||||
// ui::DragSource
|
||||
virtual void OnDragSourceCancel();
|
||||
virtual void OnDragSourceDrop();
|
||||
virtual void OnDragSourceMove();
|
||||
|
||||
private:
|
||||
// Cannot construct thusly.
|
||||
WebDragSource();
|
||||
|
||||
// OnDragSourceDrop schedules its main work to be done after IDropTarget::Drop
|
||||
// by posting a task to this function.
|
||||
void DelayedOnDragSourceDrop();
|
||||
|
||||
// Keep a reference to the window so we can translate the cursor position.
|
||||
gfx::NativeWindow source_wnd_;
|
||||
|
||||
// We use this as a channel to the web view to tell it about various drag
|
||||
// drop events that it needs to know about (such as when a drag operation it
|
||||
// initiated terminates).
|
||||
WebKit::WebView* view_;
|
||||
|
||||
DWORD effect_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(WebDragSource);
|
||||
};
|
||||
|
||||
#endif // _WEB_DRAG_SOURCE_WIN_H
|
61
libcef/web_drag_utils_win.cc
Normal file
61
libcef/web_drag_utils_win.cc
Normal file
@ -0,0 +1,61 @@
|
||||
// Copyright (c) 2010 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 "web_drag_utils_win.h"
|
||||
|
||||
#include <oleidl.h>
|
||||
#include "base/logging.h"
|
||||
|
||||
using WebKit::WebDragOperation;
|
||||
using WebKit::WebDragOperationsMask;
|
||||
using WebKit::WebDragOperationNone;
|
||||
using WebKit::WebDragOperationCopy;
|
||||
using WebKit::WebDragOperationLink;
|
||||
using WebKit::WebDragOperationMove;
|
||||
using WebKit::WebDragOperationGeneric;
|
||||
|
||||
namespace web_drag_utils_win {
|
||||
|
||||
WebDragOperation WinDragOpToWebDragOp(DWORD effect) {
|
||||
DCHECK(effect == DROPEFFECT_NONE || effect == DROPEFFECT_COPY ||
|
||||
effect == DROPEFFECT_LINK || effect == DROPEFFECT_MOVE);
|
||||
|
||||
return WinDragOpMaskToWebDragOpMask(effect);
|
||||
}
|
||||
|
||||
WebDragOperationsMask WinDragOpMaskToWebDragOpMask(DWORD effects) {
|
||||
WebDragOperationsMask ops = WebDragOperationNone;
|
||||
if (effects & DROPEFFECT_COPY)
|
||||
ops = static_cast<WebDragOperationsMask>(ops | WebDragOperationCopy);
|
||||
if (effects & DROPEFFECT_LINK)
|
||||
ops = static_cast<WebDragOperationsMask>(ops | WebDragOperationLink);
|
||||
if (effects & DROPEFFECT_MOVE)
|
||||
ops = static_cast<WebDragOperationsMask>(ops | WebDragOperationMove |
|
||||
WebDragOperationGeneric);
|
||||
return ops;
|
||||
}
|
||||
|
||||
DWORD WebDragOpToWinDragOp(WebDragOperation op) {
|
||||
DCHECK(op == WebDragOperationNone ||
|
||||
op == WebDragOperationCopy ||
|
||||
op == WebDragOperationLink ||
|
||||
op == WebDragOperationMove ||
|
||||
op == (WebDragOperationMove | WebDragOperationGeneric));
|
||||
|
||||
return WebDragOpMaskToWinDragOpMask(op);
|
||||
}
|
||||
|
||||
DWORD WebDragOpMaskToWinDragOpMask(WebDragOperationsMask ops) {
|
||||
DWORD win_ops = DROPEFFECT_NONE;
|
||||
if (ops & WebDragOperationCopy)
|
||||
win_ops |= DROPEFFECT_COPY;
|
||||
if (ops & WebDragOperationLink)
|
||||
win_ops |= DROPEFFECT_LINK;
|
||||
if (ops & (WebDragOperationMove | WebDragOperationGeneric))
|
||||
win_ops |= DROPEFFECT_MOVE;
|
||||
return win_ops;
|
||||
}
|
||||
|
||||
} // namespace web_drag_utils_win
|
||||
|
23
libcef/web_drag_utils_win.h
Normal file
23
libcef/web_drag_utils_win.h
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright (c) 2010 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 _WEB_DRAG_UTILS_WIN_H
|
||||
#define _WEB_DRAG_UTILS_WIN_H
|
||||
#pragma once
|
||||
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDragOperation.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
namespace web_drag_utils_win {
|
||||
|
||||
WebKit::WebDragOperation WinDragOpToWebDragOp(DWORD effect);
|
||||
WebKit::WebDragOperationsMask WinDragOpMaskToWebDragOpMask(DWORD effects);
|
||||
|
||||
DWORD WebDragOpToWinDragOp(WebKit::WebDragOperation op);
|
||||
DWORD WebDragOpMaskToWinDragOpMask(WebKit::WebDragOperationsMask ops);
|
||||
|
||||
} // namespace web_drag_utils_win
|
||||
|
||||
#endif // _WEB_DRAG_UTILS_WIN_H
|
131
libcef/web_drop_target_win.cc
Normal file
131
libcef/web_drop_target_win.cc
Normal file
@ -0,0 +1,131 @@
|
||||
// Copyright (c) 2011 The Chromium Embedded Framework Authors.
|
||||
// Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "web_drop_target_win.h"
|
||||
#include "cef_context.h"
|
||||
#include "web_drag_utils_win.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <shlobj.h>
|
||||
|
||||
#include "googleurl/src/gurl.h"
|
||||
#include "net/base/net_util.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDragData.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebPoint.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
|
||||
#include "ui/base/clipboard/clipboard_util_win.h"
|
||||
#include "ui/base/dragdrop/os_exchange_data.h"
|
||||
#include "ui/base/dragdrop/os_exchange_data_provider_win.h"
|
||||
#include "webkit/glue/webdropdata.h"
|
||||
#include "webkit/glue/window_open_disposition.h"
|
||||
|
||||
using WebKit::WebDragOperation;
|
||||
using WebKit::WebDragOperationNone;
|
||||
using WebKit::WebDragOperationCopy;
|
||||
using WebKit::WebDragOperationLink;
|
||||
using WebKit::WebDragOperationMove;
|
||||
using WebKit::WebDragOperationGeneric;
|
||||
using WebKit::WebPoint;
|
||||
|
||||
namespace {
|
||||
|
||||
// A helper method for getting the preferred drop effect.
|
||||
DWORD GetPreferredDropEffect(DWORD effect) {
|
||||
if (effect & DROPEFFECT_COPY)
|
||||
return DROPEFFECT_COPY;
|
||||
if (effect & DROPEFFECT_LINK)
|
||||
return DROPEFFECT_LINK;
|
||||
if (effect & DROPEFFECT_MOVE)
|
||||
return DROPEFFECT_MOVE;
|
||||
return DROPEFFECT_NONE;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
WebDropTarget::WebDropTarget(HWND source_hwnd, WebKit::WebView* view)
|
||||
: ui::DropTarget(source_hwnd),
|
||||
view_(view),
|
||||
current_wvh_(NULL),
|
||||
drag_cursor_(WebDragOperationNone) {
|
||||
}
|
||||
|
||||
WebDropTarget::~WebDropTarget() {
|
||||
}
|
||||
|
||||
DWORD WebDropTarget::OnDragEnter(IDataObject* data_object,
|
||||
DWORD key_state,
|
||||
POINT cursor_position,
|
||||
DWORD effects) {
|
||||
current_wvh_ = _Context->current_webviewhost();
|
||||
|
||||
// TODO(tc): PopulateWebDropData can be slow depending on what is in the
|
||||
// IDataObject. Maybe we can do this in a background thread.
|
||||
WebDropData drop_data(GetDragIdentity());
|
||||
WebDropData::PopulateWebDropData(data_object, &drop_data);
|
||||
|
||||
if (drop_data.url.is_empty())
|
||||
ui::OSExchangeDataProviderWin::GetPlainTextURL(data_object, &drop_data.url);
|
||||
|
||||
drag_cursor_ = WebDragOperationNone;
|
||||
|
||||
POINT client_pt = cursor_position;
|
||||
ScreenToClient(GetHWND(), &client_pt);
|
||||
WebDragOperation operation = view_->dragTargetDragEnter(
|
||||
drop_data.ToDragData(),
|
||||
drop_data.identity,
|
||||
WebPoint(client_pt.x, client_pt.y),
|
||||
WebPoint(cursor_position.x, cursor_position.y),
|
||||
web_drag_utils_win::WinDragOpMaskToWebDragOpMask(effects));
|
||||
|
||||
return web_drag_utils_win::WebDragOpToWinDragOp(operation);
|
||||
}
|
||||
|
||||
DWORD WebDropTarget::OnDragOver(IDataObject* data_object,
|
||||
DWORD key_state,
|
||||
POINT cursor_position,
|
||||
DWORD effects) {
|
||||
DCHECK(current_wvh_);
|
||||
if (current_wvh_ != _Context->current_webviewhost())
|
||||
OnDragEnter(data_object, key_state, cursor_position, effects);
|
||||
|
||||
POINT client_pt = cursor_position;
|
||||
ScreenToClient(GetHWND(), &client_pt);
|
||||
WebDragOperation operation = view_->dragTargetDragOver(
|
||||
WebPoint(client_pt.x, client_pt.y),
|
||||
WebPoint(cursor_position.x, cursor_position.y),
|
||||
web_drag_utils_win::WinDragOpMaskToWebDragOpMask(effects));
|
||||
|
||||
return web_drag_utils_win::WebDragOpToWinDragOp(operation);
|
||||
}
|
||||
|
||||
void WebDropTarget::OnDragLeave(IDataObject* data_object) {
|
||||
DCHECK(current_wvh_);
|
||||
if (current_wvh_ != _Context->current_webviewhost())
|
||||
return;
|
||||
|
||||
view_->dragTargetDragLeave();
|
||||
}
|
||||
|
||||
DWORD WebDropTarget::OnDrop(IDataObject* data_object,
|
||||
DWORD key_state,
|
||||
POINT cursor_position,
|
||||
DWORD effect) {
|
||||
DCHECK(current_wvh_);
|
||||
if (current_wvh_ != _Context->current_webviewhost())
|
||||
OnDragEnter(data_object, key_state, cursor_position, effect);
|
||||
|
||||
POINT client_pt = cursor_position;
|
||||
ScreenToClient(GetHWND(), &client_pt);
|
||||
view_->dragTargetDrop(
|
||||
WebPoint(client_pt.x, client_pt.y),
|
||||
WebPoint(cursor_position.x, cursor_position.y));
|
||||
|
||||
current_wvh_ = NULL;
|
||||
|
||||
// This isn't always correct, but at least it's a close approximation.
|
||||
// For now, we always map a move to a copy to prevent potential data loss.
|
||||
DWORD drop_effect = web_drag_utils_win::WebDragOpToWinDragOp(drag_cursor_);
|
||||
return drop_effect != DROPEFFECT_MOVE ? drop_effect : DROPEFFECT_COPY;
|
||||
}
|
68
libcef/web_drop_target_win.h
Normal file
68
libcef/web_drop_target_win.h
Normal file
@ -0,0 +1,68 @@
|
||||
// Copyright (c) 2011 The Chromium Embedded Framework Authors.
|
||||
// Portions copyright (c) 2010 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 _WEB_DROP_TARGET_WIN_H
|
||||
#define _WEB_DROP_TARGET_WIN_H
|
||||
#pragma once
|
||||
|
||||
#include "base/scoped_ptr.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDragOperation.h"
|
||||
#include "ui/base/dragdrop/drop_target.h"
|
||||
|
||||
namespace WebKit {
|
||||
class WebView;
|
||||
};
|
||||
class WebViewHost;
|
||||
|
||||
// A helper object that provides drop capabilities to a WebView. The
|
||||
// DropTarget handles drags that enter the region of the WebView by
|
||||
// passing on the events to the renderer.
|
||||
class WebDropTarget : public ui::DropTarget {
|
||||
public:
|
||||
// Create a new WebDropTarget associating it with the given HWND and
|
||||
// WebView.
|
||||
WebDropTarget(HWND source_hwnd, WebKit::WebView* view);
|
||||
virtual ~WebDropTarget();
|
||||
|
||||
void set_drag_cursor(WebKit::WebDragOperation op) {
|
||||
drag_cursor_ = op;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual DWORD OnDragEnter(IDataObject* data_object,
|
||||
DWORD key_state,
|
||||
POINT cursor_position,
|
||||
DWORD effect);
|
||||
|
||||
virtual DWORD OnDragOver(IDataObject* data_object,
|
||||
DWORD key_state,
|
||||
POINT cursor_position,
|
||||
DWORD effect);
|
||||
|
||||
virtual void OnDragLeave(IDataObject* data_object);
|
||||
|
||||
virtual DWORD OnDrop(IDataObject* data_object,
|
||||
DWORD key_state,
|
||||
POINT cursor_position,
|
||||
DWORD effect);
|
||||
|
||||
private:
|
||||
// Our associated WebView.
|
||||
WebKit::WebView* view_;
|
||||
|
||||
// We keep track of the web view host we're dragging over. If it changes
|
||||
// during a drag, we need to re-send the DragEnter message. WARNING:
|
||||
// this pointer should never be dereferenced. We only use it for comparing
|
||||
// pointers.
|
||||
WebViewHost* current_wvh_;
|
||||
|
||||
// Used to determine what cursor we should display when dragging over web
|
||||
// content area. This can be updated async during a drag operation.
|
||||
WebKit::WebDragOperation drag_cursor_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(WebDropTarget);
|
||||
};
|
||||
|
||||
#endif // _WEB_DROP_TARGET_WIN_H
|
@ -54,6 +54,7 @@ class WebViewHost : public WebWidgetHost {
|
||||
virtual bool WndProc(UINT message, WPARAM wparam, LPARAM lparam) {
|
||||
return false;
|
||||
}
|
||||
virtual void MouseEvent(UINT message, WPARAM wparam, LPARAM lparam);
|
||||
#endif
|
||||
|
||||
#if defined(TOOLKIT_USES_GTK)
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "webview_host.h"
|
||||
#include "browser_webview_delegate.h"
|
||||
#include "cef_context.h"
|
||||
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
|
||||
#include "ui/base/win/hwnd_util.h"
|
||||
@ -57,3 +58,7 @@ WebView* WebViewHost::webview() const {
|
||||
return static_cast<WebView*>(webwidget_);
|
||||
}
|
||||
|
||||
void WebViewHost::MouseEvent(UINT message, WPARAM wparam, LPARAM lparam) {
|
||||
_Context->set_current_webviewhost(this);
|
||||
WebWidgetHost::MouseEvent(message, wparam, lparam);
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ class WebWidgetHost {
|
||||
virtual bool WndProc(UINT message, WPARAM wparam, LPARAM lparam);
|
||||
|
||||
void Resize(LPARAM lparam);
|
||||
void MouseEvent(UINT message, WPARAM wparam, LPARAM lparam);
|
||||
virtual void MouseEvent(UINT message, WPARAM wparam, LPARAM lparam);
|
||||
void WheelEvent(WPARAM wparam, LPARAM lparam);
|
||||
void KeyEvent(UINT message, WPARAM wparam, LPARAM lparam);
|
||||
void CaptureLostEvent();
|
||||
|
@ -580,3 +580,8 @@ void RunDOMAccessTest(CefRefPtr<CefBrowser> browser)
|
||||
|
||||
browser->GetMainFrame()->LoadURL("http://tests/domaccess");
|
||||
}
|
||||
|
||||
void RunDragDropTest(CefRefPtr<CefBrowser> browser)
|
||||
{
|
||||
browser->GetMainFrame()->LoadURL("http://html5demos.com/drag");
|
||||
}
|
||||
|
@ -447,5 +447,6 @@ void RunHTML5VideoTest(CefRefPtr<CefBrowser> browser);
|
||||
void RunXMLHTTPRequestTest(CefRefPtr<CefBrowser> browser);
|
||||
void RunWebURLRequestTest(CefRefPtr<CefBrowser> browser);
|
||||
void RunDOMAccessTest(CefRefPtr<CefBrowser> browser);
|
||||
void RunDragDropTest(CefRefPtr<CefBrowser> browser);
|
||||
|
||||
#endif // _CEFCLIENT_H
|
||||
|
@ -84,6 +84,7 @@ BEGIN
|
||||
MENUITEM "Accelerated Layers", ID_TESTS_ACCELERATEDLAYERS
|
||||
MENUITEM "WebGL", ID_TESTS_WEBGL
|
||||
MENUITEM "HTML5 Video", ID_TESTS_HTML5VIDEO
|
||||
MENUITEM "Drag && Drop", ID_TESTS_DRAGDROP
|
||||
MENUITEM "Zoom In", ID_TESTS_ZOOM_IN
|
||||
MENUITEM "Zoom Out", ID_TESTS_ZOOM_OUT
|
||||
MENUITEM "Reset Zoom", ID_TESTS_ZOOM_RESET
|
||||
|
@ -538,6 +538,10 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
if(browser.get())
|
||||
RunHTML5VideoTest(browser);
|
||||
return 0;
|
||||
case ID_TESTS_DRAGDROP: // Test drag & drop
|
||||
if(browser.get())
|
||||
RunDragDropTest(browser);
|
||||
return 0;
|
||||
case ID_TESTS_XMLHTTPREQUEST: // Test XMLHttpRequest
|
||||
if(browser.get())
|
||||
RunXMLHTTPRequestTest(browser);
|
||||
|
@ -49,6 +49,7 @@
|
||||
#define ID_TESTS_DEVTOOLS_CLOSE 32789
|
||||
#define ID_TESTS_WEBURLREQUEST 32790
|
||||
#define ID_TESTS_DOMACCESS 32791
|
||||
#define ID_TESTS_DRAGDROP 32792
|
||||
#define IDC_STATIC -1
|
||||
#define IDS_LOGO 1000
|
||||
#define IDS_UIPLUGIN 1001
|
||||
@ -66,7 +67,7 @@
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NO_MFC 1
|
||||
#define _APS_NEXT_RESOURCE_VALUE 130
|
||||
#define _APS_NEXT_COMMAND_VALUE 32790
|
||||
#define _APS_NEXT_COMMAND_VALUE 32793
|
||||
#define _APS_NEXT_CONTROL_VALUE 1000
|
||||
#define _APS_NEXT_SYMED_VALUE 110
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user