- Add CefDragHandler to support examination of drag data and cancellation of drag requests (issue #297).

- Mac: Fix dragging of URLs by providing a default image if no drag image is supplied.

git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@279 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
Marshall Greenblatt
2011-08-22 01:31:55 +00:00
parent 88a46e0b44
commit 1b1255c92d
26 changed files with 1192 additions and 30 deletions

View File

@@ -15,6 +15,10 @@ class WebFrame;
class WebView;
}
#if defined(OS_MACOSX)
class FilePath;
#endif
namespace webkit_glue {
#if defined(OS_WIN)
@@ -28,6 +32,7 @@ BOOL SaveBitmapToFile(HBITMAP hBmp, HDC hDC, LPCTSTR file, LPBYTE lpBits);
#if defined(OS_MACOSX)
void InitializeDataPak();
FilePath GetResourcesFilePath();
#endif
// Text encoding objects must be initialized on the main thread.

View File

@@ -5,6 +5,7 @@
#include "browser_webview_delegate.h"
#import "browser_webview_mac.h"
#include "browser_impl.h"
#include "drag_data_impl.h"
#import "include/cef_application_mac.h"
#import <Cocoa/Cocoa.h>
@@ -138,6 +139,21 @@ void BrowserWebViewDelegate::startDragging(const WebDragData& data,
if (!view)
return;
WebDropData drop_data(data);
CefRefPtr<CefClient> client = browser_->GetClient();
if (client.get()) {
CefRefPtr<CefDragHandler> handler = client->GetDragHandler();
if (handler.get()) {
CefRefPtr<CefDragData> data(new CefDragDataImpl(drop_data));
if (handler->OnDragStart(browser_, data,
static_cast<CefDragHandler::DragOperationsMask>(mask))) {
browser_->UIT_GetWebView()->dragSourceSystemDragEnded();
return;
}
}
}
// By allowing nested tasks, the code below also allows Close(),
// which would deallocate |this|. The same problem can occur while
// processing -sendEvent:, so Close() is deferred in that case.
@@ -148,13 +164,16 @@ void BrowserWebViewDelegate::startDragging(const WebDragData& data,
// The drag invokes a nested event loop, arrange to continue
// processing events.
MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current());
NSDragOperation op_mask = static_cast<NSDragOperation>(mask);
const SkBitmap& bitmap = gfx::CGImageToSkBitmap(image.getCGImageRef());
CGColorSpaceRef color_space = base::mac::GetSystemColorSpace();
NSImage* ns_image = gfx::SkBitmapToNSImageWithColorSpace(bitmap, color_space);
NSImage* ns_image = nil;
if (!image.isNull()) {
const SkBitmap& bitmap = gfx::CGImageToSkBitmap(image.getCGImageRef());
CGColorSpaceRef color_space = base::mac::GetSystemColorSpace();
ns_image = gfx::SkBitmapToNSImageWithColorSpace(bitmap, color_space);
}
NSPoint offset = NSPointFromCGPoint(gfx::Point(image_offset).ToCGPoint());
[view startDragWithDropData:WebDropData(data)
dragOperationMask:op_mask
[view startDragWithDropData:drop_data
dragOperationMask:static_cast<NSDragOperation>(mask)
image:ns_image
offset:offset];
}

View File

@@ -12,6 +12,7 @@
#include "browser_impl.h"
#include "browser_webview_delegate.h"
#include "cef_context.h"
#include "drag_data_impl.h"
#include "web_drop_target_win.h"
#include <objidl.h>
@@ -190,8 +191,23 @@ void BrowserWebViewDelegate::startDragging(
return;
}
WebDropData drop_data(data);
CefRefPtr<CefClient> client = browser_->GetClient();
if (client.get()) {
CefRefPtr<CefDragHandler> handler = client->GetDragHandler();
if (handler.get()) {
CefRefPtr<CefDragData> data(new CefDragDataImpl(drop_data));
if (handler->OnDragStart(browser_, data,
static_cast<CefDragHandler::DragOperationsMask>(mask))) {
EndDragging();
return;
}
}
}
drag_delegate_ = new BrowserDragDelegate(this);
drag_delegate_->StartDragging(WebDropData(data), mask, image.getSkBitmap(),
drag_delegate_->StartDragging(drop_data, mask, image.getSkBitmap(),
image_offset);
}
@@ -563,8 +579,7 @@ end:
void BrowserWebViewDelegate::RegisterDragDrop() {
DCHECK(!drop_target_);
drop_target_ = new WebDropTarget(browser_->UIT_GetWebViewWndHandle(),
browser_->UIT_GetWebView());
drop_target_ = new WebDropTarget(browser_);
}
void BrowserWebViewDelegate::RevokeDragDrop() {

78
libcef/drag_data_impl.cc Normal file
View File

@@ -0,0 +1,78 @@
// Copyright (c) 2011 The Chromium Embedded Framework 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_data_impl.h"
CefDragDataImpl::CefDragDataImpl(const WebDropData& data)
: data_(data)
{
}
bool CefDragDataImpl::IsLink()
{
return (data_.url.is_valid() && data_.file_extension.empty());
}
bool CefDragDataImpl::IsFragment()
{
return (!data_.url.is_valid() && data_.file_extension.empty() &&
data_.filenames.empty());
}
bool CefDragDataImpl::IsFile()
{
return (!data_.file_extension.empty() || !data_.filenames.empty());
}
CefString CefDragDataImpl::GetLinkURL()
{
return data_.url.spec();
}
CefString CefDragDataImpl::GetLinkTitle()
{
return data_.url_title;
}
CefString CefDragDataImpl::GetLinkMetadata()
{
return data_.download_metadata;
}
CefString CefDragDataImpl::GetFragmentText()
{
return data_.plain_text;
}
CefString CefDragDataImpl::GetFragmentHtml()
{
return data_.text_html;
}
CefString CefDragDataImpl::GetFragmentBaseURL()
{
return data_.html_base_url.spec();
}
CefString CefDragDataImpl::GetFileExtension()
{
return data_.file_extension;
}
CefString CefDragDataImpl::GetFileName()
{
return data_.file_description_filename;
}
bool CefDragDataImpl::GetFileNames(std::vector<CefString>& names)
{
if (data_.filenames.empty())
return false;
std::vector<string16>::const_iterator it = data_.filenames.begin();
for (; it != data_.filenames.end(); ++it)
names.push_back(*it);
return true;
}

36
libcef/drag_data_impl.h Normal file
View File

@@ -0,0 +1,36 @@
// Copyright (c) 2011 The Chromium Embedded Framework 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_DATA_IMPL_H
#define _DRAG_DATA_IMPL_H
#include "../include/cef.h"
#include "webkit/glue/webdropdata.h"
// Implementation of CefDragData.
class CefDragDataImpl : public CefDragData
{
public:
explicit CefDragDataImpl(const WebDropData& data);
virtual bool IsLink();
virtual bool IsFragment();
virtual bool IsFile();
virtual CefString GetLinkURL();
virtual CefString GetLinkTitle();
virtual CefString GetLinkMetadata();
virtual CefString GetFragmentText();
virtual CefString GetFragmentHtml();
virtual CefString GetFragmentBaseURL();
virtual CefString GetFileExtension();
virtual CefString GetFileName();
virtual bool GetFileNames(std::vector<CefString>& names);
protected:
WebDropData data_;
IMPLEMENT_REFCOUNTING(CefDragDataImpl);
};
#endif // _DRAG_DATA_IMPL_H

View File

@@ -4,6 +4,7 @@
// found in the LICENSE file.
#include "browser_impl.h"
#include "browser_webkit_glue.h"
#import "browser_webview_mac.h"
#include "drag_download_util.h"
#include "download_util.h"
@@ -140,6 +141,14 @@ void PromiseWriterTask::Run() {
dropData_.reset(new WebDropData(*dropData));
DCHECK(dropData_.get());
if (image == nil) {
// No drag image was provided so create one.
FilePath path = webkit_glue::GetResourcesFilePath();
path = path.AppendASCII("urlIcon.png");
image = [[NSImage alloc]
initWithContentsOfFile:SysUTF8ToNSString(path.value())];
}
dragImage_.reset([image retain]);
imageOffset_ = offset;

View File

@@ -6,6 +6,7 @@
#include "browser_impl.h"
#import "browser_webview_mac.h"
#include "cef_context.h"
#include "drag_data_impl.h"
#import "web_drop_target_mac.h"
#import "web_drag_utils_mac.h"
@@ -30,8 +31,10 @@ using WebKit::WebView;
// drag&drop messages to WebCore and handle navigation on a successful drop
// (if necessary).
- (id)initWithWebView:(BrowserWebView*)view {
if ((self = [super init]))
if ((self = [super init])) {
view_ = view;
canceled_ = false;
}
return self;
}
@@ -86,17 +89,34 @@ using WebKit::WebView;
WebView* webview = view_.browser->UIT_GetWebView();
// Fill out a WebDropData from pasteboard.
WebDropData data;
[self populateWebDropData:&data fromPasteboard:[info draggingPasteboard]];
WebDropData drop_data;
[self populateWebDropData:&drop_data
fromPasteboard:[info draggingPasteboard]];
NSDragOperation mask = [info draggingSourceOperationMask];
canceled_ = false;
CefRefPtr<CefClient> client = view_.browser->GetClient();
if (client.get()) {
CefRefPtr<CefDragHandler> handler = client->GetDragHandler();
if (handler.get()) {
CefRefPtr<CefDragData> data(new CefDragDataImpl(drop_data));
if (handler->OnDragEnter(view_.browser, data,
static_cast<CefDragHandler::DragOperationsMask>(mask))) {
canceled_ = true;
return NSDragOperationNone;
}
}
}
// Create the appropriate mouse locations for WebCore. The draggingLocation
// is in window coordinates. Both need to be flipped.
NSPoint windowPoint = [info draggingLocation];
NSPoint viewPoint = [self flipWindowPointToView:windowPoint view:view];
NSPoint screenPoint = [self flipWindowPointToScreen:windowPoint view:view];
NSDragOperation mask = [info draggingSourceOperationMask];
WebDragOperation op =
webview->dragTargetDragEnter(data.ToDragData(),
webview->dragTargetDragEnter(drop_data.ToDragData(),
WebPoint(viewPoint.x, viewPoint.y),
WebPoint(screenPoint.x, screenPoint.y),
static_cast<WebDragOperationsMask>(mask));
@@ -108,6 +128,9 @@ using WebKit::WebView;
if (current_wvh_ != _Context->current_webviewhost())
return;
if (canceled_)
return;
WebView* webview = view_.browser->UIT_GetWebView();
// Nothing to do in the interstitial case.
@@ -127,6 +150,9 @@ using WebKit::WebView;
return NSDragOperationNone;
}
if (canceled_)
return NSDragOperationNone;
WebView* webview = view_.browser->UIT_GetWebView();
// Create the appropriate mouse locations for WebCore. The draggingLocation

View File

@@ -3,9 +3,11 @@
// 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 "browser_impl.h"
#include "cef_context.h"
#include "drag_data_impl.h"
#include "web_drag_utils_win.h"
#include "web_drop_target_win.h"
#include <windows.h>
#include <shlobj.h>
@@ -28,6 +30,7 @@ using WebKit::WebDragOperationLink;
using WebKit::WebDragOperationMove;
using WebKit::WebDragOperationGeneric;
using WebKit::WebPoint;
using WebKit::WebView;
namespace {
@@ -44,11 +47,12 @@ DWORD GetPreferredDropEffect(DWORD effect) {
} // namespace
WebDropTarget::WebDropTarget(HWND source_hwnd, WebKit::WebView* view)
: ui::DropTarget(source_hwnd),
view_(view),
WebDropTarget::WebDropTarget(CefBrowserImpl* browser)
: ui::DropTarget(browser->UIT_GetWebViewWndHandle()),
browser_(browser),
current_wvh_(NULL),
drag_cursor_(WebDragOperationNone) {
drag_cursor_(WebDragOperationNone),
canceled_(false) {
}
WebDropTarget::~WebDropTarget() {
@@ -69,15 +73,33 @@ DWORD WebDropTarget::OnDragEnter(IDataObject* data_object,
if (drop_data.url.is_empty())
ui::OSExchangeDataProviderWin::GetPlainTextURL(data_object, &drop_data.url);
WebKit::WebDragOperationsMask mask =
web_drag_utils_win::WinDragOpMaskToWebDragOpMask(effects);
canceled_ = false;
CefRefPtr<CefClient> client = browser_->GetClient();
if (client.get()) {
CefRefPtr<CefDragHandler> handler = client->GetDragHandler();
if (handler.get()) {
CefRefPtr<CefDragData> data(new CefDragDataImpl(drop_data));
if (handler->OnDragEnter(browser_, data,
static_cast<CefDragHandler::DragOperationsMask>(mask))) {
canceled_ = true;
return DROPEFFECT_NONE;
}
}
}
drag_cursor_ = WebDragOperationNone;
POINT client_pt = cursor_position;
ScreenToClient(GetHWND(), &client_pt);
WebDragOperation operation = view_->dragTargetDragEnter(
WebDragOperation operation = browser_->UIT_GetWebView()->dragTargetDragEnter(
drop_data.ToDragData(),
WebPoint(client_pt.x, client_pt.y),
WebPoint(cursor_position.x, cursor_position.y),
web_drag_utils_win::WinDragOpMaskToWebDragOpMask(effects));
mask);
return web_drag_utils_win::WebDragOpToWinDragOp(operation);
}
@@ -90,9 +112,12 @@ DWORD WebDropTarget::OnDragOver(IDataObject* data_object,
if (current_wvh_ != _Context->current_webviewhost())
OnDragEnter(data_object, key_state, cursor_position, effects);
if (canceled_)
return DROPEFFECT_NONE;
POINT client_pt = cursor_position;
ScreenToClient(GetHWND(), &client_pt);
WebDragOperation operation = view_->dragTargetDragOver(
WebDragOperation operation = browser_->UIT_GetWebView()->dragTargetDragOver(
WebPoint(client_pt.x, client_pt.y),
WebPoint(cursor_position.x, cursor_position.y),
web_drag_utils_win::WinDragOpMaskToWebDragOpMask(effects));
@@ -105,7 +130,10 @@ void WebDropTarget::OnDragLeave(IDataObject* data_object) {
if (current_wvh_ != _Context->current_webviewhost())
return;
view_->dragTargetDragLeave();
if (canceled_)
return;
browser_->UIT_GetWebView()->dragTargetDragLeave();
}
DWORD WebDropTarget::OnDrop(IDataObject* data_object,
@@ -118,7 +146,7 @@ DWORD WebDropTarget::OnDrop(IDataObject* data_object,
POINT client_pt = cursor_position;
ScreenToClient(GetHWND(), &client_pt);
view_->dragTargetDrop(
browser_->UIT_GetWebView()->dragTargetDrop(
WebPoint(client_pt.x, client_pt.y),
WebPoint(cursor_position.x, cursor_position.y));

View File

@@ -11,9 +11,7 @@
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDragOperation.h"
#include "ui/base/dragdrop/drop_target.h"
namespace WebKit {
class WebView;
};
class CefBrowserImpl;
class WebViewHost;
// A helper object that provides drop capabilities to a WebView. The
@@ -23,7 +21,7 @@ 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);
WebDropTarget(CefBrowserImpl* browser);
virtual ~WebDropTarget();
void set_drag_cursor(WebKit::WebDragOperation op) {
@@ -49,8 +47,8 @@ class WebDropTarget : public ui::DropTarget {
DWORD effect);
private:
// Our associated WebView.
WebKit::WebView* view_;
// Our associated CefBrowserImpl.
CefBrowserImpl* browser_;
// 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:
@@ -62,6 +60,9 @@ class WebDropTarget : public ui::DropTarget {
// content area. This can be updated async during a drag operation.
WebKit::WebDragOperation drag_cursor_;
// True if the drag has been canceled.
bool canceled_;
DISALLOW_COPY_AND_ASSIGN(WebDropTarget);
};