Mac:
- Add HTML5 drag&drop support (issue #140). - Client application must now provide NSApplication implementing CefAppProtocol and call CefRunMessageLoop() (issue #248). git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@269 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
parent
b2100d27bd
commit
7d006a8dd6
24
cef.gyp
24
cef.gyp
|
@ -165,6 +165,7 @@
|
|||
],
|
||||
},
|
||||
'sources': [
|
||||
'include/cef_application_mac.h',
|
||||
'tests/cefclient/cefclient_mac.mm',
|
||||
'tests/cefclient/client_handler_mac.mm',
|
||||
'tests/cefclient/resource_util_mac.mm',
|
||||
|
@ -413,6 +414,11 @@
|
|||
],
|
||||
'xcode_settings': {
|
||||
'INSTALL_PATH': '@executable_path',
|
||||
# The libcef_static target contains ObjC categories. Passing the -ObjC flag
|
||||
# is necessary to properly load them and avoid a "selector not recognized"
|
||||
# runtime error. See http://developer.apple.com/library/mac/#qa/qa1490/_index.html
|
||||
# for more information.
|
||||
'OTHER_LDFLAGS': ['-Wl,-ObjC'],
|
||||
},
|
||||
'conditions': [
|
||||
['OS=="win"', {
|
||||
|
@ -680,6 +686,8 @@
|
|||
'libcef/cef_time_util.h',
|
||||
'libcef/drag_download_file.cc',
|
||||
'libcef/drag_download_file.h',
|
||||
'libcef/drag_download_util.cc',
|
||||
'libcef/drag_download_util.h',
|
||||
'libcef/dom_storage_area.cc',
|
||||
'libcef/dom_storage_area.h',
|
||||
'libcef/dom_storage_common.h',
|
||||
|
@ -693,6 +701,8 @@
|
|||
'libcef/dom_event_impl.h',
|
||||
'libcef/dom_node_impl.cc',
|
||||
'libcef/dom_node_impl.h',
|
||||
'libcef/download_util.cc',
|
||||
'libcef/download_util.h',
|
||||
'libcef/external_protocol_handler.h',
|
||||
'libcef/http_header_utils.cc',
|
||||
'libcef/http_header_utils.h',
|
||||
|
@ -753,6 +763,7 @@
|
|||
}],
|
||||
[ 'OS=="mac"', {
|
||||
'sources': [
|
||||
'include/cef_application_mac.h',
|
||||
'include/internal/cef_types_mac.h',
|
||||
'include/internal/cef_mac.h',
|
||||
'libcef/browser_impl_mac.mm',
|
||||
|
@ -766,6 +777,19 @@
|
|||
'libcef/external_protocol_handler_mac.mm',
|
||||
'libcef/webview_host_mac.mm',
|
||||
'libcef/webwidget_host_mac.mm',
|
||||
'libcef/web_drag_source_mac.h',
|
||||
'libcef/web_drag_source_mac.mm',
|
||||
'libcef/web_drag_utils_mac.h',
|
||||
'libcef/web_drag_utils_mac.mm',
|
||||
'libcef/web_drop_target_mac.h',
|
||||
'libcef/web_drop_target_mac.mm',
|
||||
# Build necessary Mozilla sources
|
||||
'../third_party/mozilla/NSPasteboard+Utils.h',
|
||||
'../third_party/mozilla/NSPasteboard+Utils.mm',
|
||||
'../third_party/mozilla/NSString+Utils.h',
|
||||
'../third_party/mozilla/NSString+Utils.mm',
|
||||
'../third_party/mozilla/NSURL+Utils.h',
|
||||
'../third_party/mozilla/NSURL+Utils.m',
|
||||
],
|
||||
}],
|
||||
[ 'OS=="linux" or OS=="freebsd" or OS=="openbsd"', {
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
// Copyright (c) 2011 Marshall A. Greenblatt. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the name Chromium Embedded
|
||||
// Framework nor the names of its contributors may be used to endorse
|
||||
// or promote products derived from this software without specific prior
|
||||
// written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef _CEF_APPLICATION_MAC_H
|
||||
#define _CEF_APPLICATION_MAC_H
|
||||
#pragma once
|
||||
|
||||
#include "cef.h"
|
||||
|
||||
#if defined(OS_MACOSX) && defined(__OBJC__)
|
||||
|
||||
#ifdef BUILDING_CEF_SHARED
|
||||
|
||||
// Use the existing CrAppProtocol definition.
|
||||
#include "base/message_pump_mac.h"
|
||||
|
||||
#else // BUILDING_CEF_SHARED
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
// Copy of CrAppProtocol definition from base/message_pump_mac.h.
|
||||
@protocol CrAppProtocol
|
||||
// Must return true if -[NSApplication sendEvent:] is currently on the stack.
|
||||
- (BOOL)isHandlingSendEvent;
|
||||
@end
|
||||
|
||||
#endif // BUILDING_CEF_SHARED
|
||||
|
||||
// All CEF client applications must subclass NSApplication and implement this
|
||||
// protocol.
|
||||
@protocol CefAppProtocol<CrAppProtocol>
|
||||
- (void)setHandlingSendEvent:(BOOL)handlingSendEvent;
|
||||
@end
|
||||
|
||||
// Controls the state of |isHandlingSendEvent| in the event loop so that it is
|
||||
// reset properly.
|
||||
class CefScopedSendingEvent {
|
||||
public:
|
||||
CefScopedSendingEvent()
|
||||
: app_(static_cast<NSApplication<CefAppProtocol>*>(
|
||||
[NSApplication sharedApplication])),
|
||||
handling_([app_ isHandlingSendEvent]) {
|
||||
[app_ setHandlingSendEvent:YES];
|
||||
}
|
||||
~CefScopedSendingEvent() {
|
||||
[app_ setHandlingSendEvent:handling_];
|
||||
}
|
||||
|
||||
private:
|
||||
NSApplication<CefAppProtocol>* app_;
|
||||
BOOL handling_;
|
||||
};
|
||||
|
||||
#endif // defined(OS_MACOSX) && defined(__OBJC__)
|
||||
|
||||
#endif // _CEF_APPLICATION_MAC_H
|
|
@ -9,6 +9,8 @@
|
|||
#include "browser_webview_delegate.h"
|
||||
#include "cef_thread.h"
|
||||
#include "drag_download_file.h"
|
||||
#include "drag_download_util.h"
|
||||
#include "download_util.h"
|
||||
#include "web_drag_source_win.h"
|
||||
#include "web_drag_utils_win.h"
|
||||
#include "web_drop_target_win.h"
|
||||
|
@ -17,16 +19,8 @@
|
|||
|
||||
#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/WebDocument.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
|
||||
|
@ -71,214 +65,6 @@ LRESULT CALLBACK MsgFilterProc(int code, WPARAM wparam, LPARAM lparam) {
|
|||
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 {
|
||||
|
@ -406,21 +192,22 @@ void BrowserDragDelegate::PrepareDragForDownload(
|
|||
string16 mime_type;
|
||||
FilePath file_name;
|
||||
GURL download_url;
|
||||
if (!ParseDownloadMetadata(drop_data.download_metadata,
|
||||
&mime_type,
|
||||
&file_name,
|
||||
&download_url))
|
||||
if (!drag_download_util::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);
|
||||
download_util::GenerateFileName(download_url,
|
||||
content_disposition,
|
||||
std::string(),
|
||||
UTF16ToUTF8(mime_type),
|
||||
std::string(),
|
||||
&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.
|
||||
|
|
|
@ -700,6 +700,8 @@ void CefBrowserImpl::UIT_DestroyBrowser()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
UIT_GetWebViewDelegate()->RevokeDragDrop();
|
||||
#else
|
||||
// Call OnBeforeClose() here for platforms that don't support modal dialogs.
|
||||
if (client_.get()) {
|
||||
|
@ -711,8 +713,6 @@ void CefBrowserImpl::UIT_DestroyBrowser()
|
|||
}
|
||||
#endif
|
||||
|
||||
UIT_GetWebViewDelegate()->RevokeDragDrop();
|
||||
|
||||
// If the current browser window is a dev tools client then disconnect from
|
||||
// the agent and destroy the client before destroying the window.
|
||||
UIT_DestroyDevToolsClient();
|
||||
|
|
|
@ -59,7 +59,6 @@ void CefBrowserImpl::UIT_CreateBrowser(const CefString& url)
|
|||
WebViewHost::Create(window_info_.m_ParentWidget, gfx::Rect(),
|
||||
delegate_.get(), NULL, dev_tools_agent_.get(),
|
||||
prefs));
|
||||
delegate_->RegisterDragDrop();
|
||||
|
||||
if (!settings_.developer_tools_disabled)
|
||||
dev_tools_agent_->SetWebView(webviewhost_->webview());
|
||||
|
|
|
@ -86,7 +86,6 @@ void CefBrowserImpl::UIT_CreateBrowser(const CefString& url)
|
|||
webviewhost_.reset(
|
||||
WebViewHost::Create(parentView, contentRect, delegate_.get(),
|
||||
NULL, dev_tools_agent_.get(), prefs));
|
||||
delegate_->RegisterDragDrop();
|
||||
|
||||
if (!settings_.developer_tools_disabled)
|
||||
dev_tools_agent_->SetWebView(webviewhost_->webview());
|
||||
|
|
|
@ -34,12 +34,10 @@
|
|||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebData.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDataSource.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDragData.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFileError.h"
|
||||
#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"
|
||||
|
@ -61,7 +59,6 @@
|
|||
#include "webkit/appcache/web_application_cache_host_impl.h"
|
||||
#include "webkit/glue/glue_serialize.h"
|
||||
#include "webkit/glue/media/video_renderer_impl.h"
|
||||
#include "webkit/glue/webdropdata.h"
|
||||
#include "webkit/glue/webpreferences.h"
|
||||
#include "webkit/glue/webkit_glue.h"
|
||||
#include "webkit/glue/webmediaplayer_impl.h"
|
||||
|
@ -71,7 +68,6 @@
|
|||
#include "webkit/plugins/npapi/webplugin_impl.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// TODO(port): make these files work everywhere.
|
||||
#include "browser_drag_delegate_win.h"
|
||||
#include "web_drop_target_win.h"
|
||||
#endif
|
||||
|
@ -84,8 +80,6 @@ using WebKit::WebContextMenuData;
|
|||
using WebKit::WebCookieJar;
|
||||
using WebKit::WebData;
|
||||
using WebKit::WebDataSource;
|
||||
using WebKit::WebDragData;
|
||||
using WebKit::WebDragOperationsMask;
|
||||
using WebKit::WebEditingAction;
|
||||
using WebKit::WebFileChooserParams;
|
||||
using WebKit::WebFileSystem;
|
||||
|
@ -93,7 +87,6 @@ using WebKit::WebFileSystemCallbacks;
|
|||
using WebKit::WebFormElement;
|
||||
using WebKit::WebFrame;
|
||||
using WebKit::WebHistoryItem;
|
||||
using WebKit::WebImage;
|
||||
using WebKit::WebMediaPlayer;
|
||||
using WebKit::WebMediaPlayerClient;
|
||||
using WebKit::WebNavigationType;
|
||||
|
@ -446,27 +439,6 @@ void BrowserWebViewDelegate::setToolTipText(
|
|||
GetWidgetHost()->SetTooltipText(tooltipStr);
|
||||
}
|
||||
|
||||
void BrowserWebViewDelegate::startDragging(
|
||||
const WebDragData& data,
|
||||
WebDragOperationsMask mask,
|
||||
const WebImage& image,
|
||||
const WebPoint& image_offset) {
|
||||
#if defined(OS_WIN)
|
||||
// Dragging is not supported when window rendering is disabled.
|
||||
if (browser_->IsWindowRenderingDisabled()) {
|
||||
EndDragging();
|
||||
return;
|
||||
}
|
||||
|
||||
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() {
|
||||
CefRefPtr<CefClient> client = browser_->GetClient();
|
||||
if (client.get()) {
|
||||
|
@ -986,22 +958,6 @@ void BrowserWebViewDelegate::SetSelectTrailingWhitespaceEnabled(bool enabled) {
|
|||
// allows both.
|
||||
}
|
||||
|
||||
void BrowserWebViewDelegate::RegisterDragDrop() {
|
||||
#if defined(OS_WIN)
|
||||
// TODO(port): add me once drag and drop works.
|
||||
DCHECK(!drop_target_);
|
||||
drop_target_ = new WebDropTarget(browser_->UIT_GetWebViewWndHandle(),
|
||||
browser_->UIT_GetWebView());
|
||||
#endif
|
||||
}
|
||||
|
||||
void BrowserWebViewDelegate::RevokeDragDrop() {
|
||||
#if defined(OS_WIN)
|
||||
if (drop_target_.get())
|
||||
::RevokeDragDrop(browser_->UIT_GetWebViewWndHandle());
|
||||
#endif
|
||||
}
|
||||
|
||||
void BrowserWebViewDelegate::SetCustomPolicyDelegate(bool is_custom,
|
||||
bool is_permissive) {
|
||||
policy_delegate_enabled_ = is_custom;
|
||||
|
@ -1062,13 +1018,6 @@ 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.
|
||||
|
|
|
@ -214,6 +214,13 @@ class BrowserWebViewDelegate : public WebKit::WebViewClient,
|
|||
|
||||
// Additional accessors
|
||||
#if defined(OS_WIN)
|
||||
// Sets the webview as a drop target.
|
||||
void RegisterDragDrop();
|
||||
void RevokeDragDrop();
|
||||
|
||||
// Called after dragging has finished.
|
||||
void EndDragging();
|
||||
|
||||
BrowserDragDelegate* drag_delegate() { return drag_delegate_.get(); }
|
||||
WebDropTarget* drop_target() { return drop_target_.get(); }
|
||||
#endif
|
||||
|
@ -222,12 +229,6 @@ class BrowserWebViewDelegate : public WebKit::WebViewClient,
|
|||
pending_extra_data_.reset(extra_data);
|
||||
}
|
||||
|
||||
// Sets the webview as a drop target.
|
||||
void RegisterDragDrop();
|
||||
void RevokeDragDrop();
|
||||
|
||||
void ResetDragDrop();
|
||||
|
||||
void SetCustomPolicyDelegate(bool is_custom, bool is_permissive);
|
||||
void WaitForPolicyDelegate();
|
||||
|
||||
|
@ -255,9 +256,6 @@ class BrowserWebViewDelegate : public WebKit::WebViewClient,
|
|||
void ClosePopupMenu();
|
||||
#endif
|
||||
|
||||
// Called after dragging has finished.
|
||||
void EndDragging();
|
||||
|
||||
protected:
|
||||
// Default handling of JavaScript messages.
|
||||
void ShowJavaScriptAlert(WebKit::WebFrame* webframe,
|
||||
|
|
|
@ -177,6 +177,15 @@ WebRect BrowserWebViewDelegate::windowResizerRect() {
|
|||
return WebRect();
|
||||
}
|
||||
|
||||
void BrowserWebViewDelegate::startDragging(
|
||||
const WebDragData& data,
|
||||
WebDragOperationsMask mask,
|
||||
const WebImage& image,
|
||||
const WebPoint& image_offset) {
|
||||
// TODO(port): Support drag and drop.
|
||||
browser_->UIT_GetWebView()->dragSourceSystemDragEnded();
|
||||
}
|
||||
|
||||
void BrowserWebViewDelegate::runModal() {
|
||||
NOTIMPLEMENTED();
|
||||
}
|
||||
|
|
|
@ -3,23 +3,35 @@
|
|||
// found in the LICENSE file.
|
||||
|
||||
#include "browser_webview_delegate.h"
|
||||
#import "browser_webview_mac.h"
|
||||
#include "browser_impl.h"
|
||||
#import "include/cef_application_mac.h"
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include "base/mac/mac_util.h"
|
||||
#include "base/sys_string_conversions.h"
|
||||
#include "skia/ext/skia_utils_mac.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDragData.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebImage.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebPoint.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebPopupMenu.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
|
||||
#include "webkit/glue/webcursor.h"
|
||||
#include "webkit/glue/webdropdata.h"
|
||||
#include "webkit/plugins/npapi/plugin_list.h"
|
||||
#include "webkit/plugins/npapi/webplugin_delegate_impl.h"
|
||||
#include "webkit/glue/webmenurunner_mac.h"
|
||||
|
||||
using WebKit::WebCursorInfo;
|
||||
using WebKit::WebDragData;
|
||||
using WebKit::WebDragOperationsMask;
|
||||
using WebKit::WebExternalPopupMenu;
|
||||
using WebKit::WebExternalPopupMenuClient;
|
||||
using WebKit::WebImage;
|
||||
using WebKit::WebNavigationPolicy;
|
||||
using WebKit::WebPoint;
|
||||
using WebKit::WebPopupMenuInfo;
|
||||
using WebKit::WebRect;
|
||||
using WebKit::WebWidget;
|
||||
|
@ -109,6 +121,39 @@ WebRect BrowserWebViewDelegate::windowResizerRect() {
|
|||
return gfx::Rect(NSRectToCGRect(resize_rect));
|
||||
}
|
||||
|
||||
void BrowserWebViewDelegate::startDragging(const WebDragData& data,
|
||||
WebDragOperationsMask mask,
|
||||
const WebImage& image,
|
||||
const WebPoint& image_offset) {
|
||||
WebWidgetHost* host = GetWidgetHost();
|
||||
if (!host)
|
||||
return;
|
||||
|
||||
BrowserWebView *view = static_cast<BrowserWebView*>(host->view_handle());
|
||||
if (!view)
|
||||
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.
|
||||
// Drags from web content do not come via -sendEvent:, this sets the
|
||||
// same flag -sendEvent: would.
|
||||
CefScopedSendingEvent sendingEventScoper;
|
||||
|
||||
// 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);
|
||||
NSPoint offset = NSPointFromCGPoint(gfx::Point(image_offset).ToCGPoint());
|
||||
[view startDragWithDropData:WebDropData(data)
|
||||
dragOperationMask:op_mask
|
||||
image:ns_image
|
||||
offset:offset];
|
||||
}
|
||||
|
||||
void BrowserWebViewDelegate::runModal() {
|
||||
NOTIMPLEMENTED();
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2008-2009 The Chromium Embedded Framework Authors.
|
||||
// Copyright (c) 2011 The Chromium Embedded Framework Authors.
|
||||
// Portions copyright (c) 2006-2008 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.
|
||||
|
@ -7,10 +7,12 @@
|
|||
// as the WebViewDelegate for the BrowserWebHost. The host is expected to
|
||||
// have initialized a MessageLoop before these methods are called.
|
||||
|
||||
#include "browser_webview_delegate.h"
|
||||
#include "browser_drag_delegate_win.h"
|
||||
#include "browser_navigation_controller.h"
|
||||
#include "browser_impl.h"
|
||||
#include "browser_webview_delegate.h"
|
||||
#include "cef_context.h"
|
||||
#include "web_drop_target_win.h"
|
||||
|
||||
#include <objidl.h>
|
||||
#include <shlobj.h>
|
||||
|
@ -21,7 +23,10 @@
|
|||
#include "net/base/net_errors.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebContextMenuData.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDragData.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebImage.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebPoint.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebRect.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
|
||||
#include "ui/gfx/gdi_util.h"
|
||||
|
@ -38,10 +43,14 @@
|
|||
using webkit::npapi::WebPluginDelegateImpl;
|
||||
using WebKit::WebContextMenuData;
|
||||
using WebKit::WebCursorInfo;
|
||||
using WebKit::WebDragData;
|
||||
using WebKit::WebDragOperationsMask;
|
||||
using WebKit::WebExternalPopupMenu;
|
||||
using WebKit::WebExternalPopupMenuClient;
|
||||
using WebKit::WebFrame;
|
||||
using WebKit::WebImage;
|
||||
using WebKit::WebNavigationPolicy;
|
||||
using WebKit::WebPoint;
|
||||
using WebKit::WebPopupMenuInfo;
|
||||
using WebKit::WebRect;
|
||||
using WebKit::WebWidget;
|
||||
|
@ -169,6 +178,22 @@ WebRect BrowserWebViewDelegate::windowResizerRect() {
|
|||
return WebRect();
|
||||
}
|
||||
|
||||
void BrowserWebViewDelegate::startDragging(
|
||||
const WebDragData& data,
|
||||
WebDragOperationsMask mask,
|
||||
const WebImage& image,
|
||||
const WebPoint& image_offset) {
|
||||
// Dragging is not supported when window rendering is disabled.
|
||||
if (browser_->IsWindowRenderingDisabled()) {
|
||||
EndDragging();
|
||||
return;
|
||||
}
|
||||
|
||||
drag_delegate_ = new BrowserDragDelegate(this);
|
||||
drag_delegate_->StartDragging(WebDropData(data), mask, image.getSkBitmap(),
|
||||
image_offset);
|
||||
}
|
||||
|
||||
void BrowserWebViewDelegate::runModal() {
|
||||
WebWidgetHost* host = GetWidgetHost();
|
||||
if (!host)
|
||||
|
@ -535,6 +560,22 @@ end:
|
|||
|
||||
// Private methods ------------------------------------------------------------
|
||||
|
||||
void BrowserWebViewDelegate::RegisterDragDrop() {
|
||||
DCHECK(!drop_target_);
|
||||
drop_target_ = new WebDropTarget(browser_->UIT_GetWebViewWndHandle(),
|
||||
browser_->UIT_GetWebView());
|
||||
}
|
||||
|
||||
void BrowserWebViewDelegate::RevokeDragDrop() {
|
||||
if (drop_target_.get())
|
||||
::RevokeDragDrop(browser_->UIT_GetWebViewWndHandle());
|
||||
}
|
||||
|
||||
void BrowserWebViewDelegate::EndDragging() {
|
||||
browser_->UIT_GetWebView()->dragSourceSystemDragEnded();
|
||||
drag_delegate_ = NULL;
|
||||
}
|
||||
|
||||
void BrowserWebViewDelegate::ShowJavaScriptAlert(WebFrame* webframe,
|
||||
const CefString& message)
|
||||
{
|
||||
|
|
|
@ -3,8 +3,12 @@
|
|||
// found in the LICENSE file.
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#include "base/memory/scoped_nsobject.h"
|
||||
|
||||
class CefBrowserImpl;
|
||||
@class WebDragSource;
|
||||
@class WebDropTarget;
|
||||
struct WebDropData;
|
||||
|
||||
// A view to wrap the WebCore view and help it live in a Cocoa world. The
|
||||
// (rough) equivalent of Apple's WebView.
|
||||
|
@ -13,6 +17,9 @@ class CefBrowserImpl;
|
|||
@private
|
||||
CefBrowserImpl *browser_; // weak
|
||||
NSTrackingArea *trackingArea_;
|
||||
|
||||
scoped_nsobject<WebDragSource> dragSource_;
|
||||
scoped_nsobject<WebDropTarget> dropTarget_;
|
||||
}
|
||||
|
||||
- (void)mouseDown:(NSEvent *)theEvent;
|
||||
|
@ -33,6 +40,12 @@ class CefBrowserImpl;
|
|||
- (BOOL)isOpaque;
|
||||
- (void)setFrame:(NSRect)frameRect;
|
||||
|
||||
// Called from BrowserWebViewDelegate::startDragging() to initiate dragging.
|
||||
- (void)startDragWithDropData:(const WebDropData&)dropData
|
||||
dragOperationMask:(NSDragOperation)operationMask
|
||||
image:(NSImage*)image
|
||||
offset:(NSPoint)offset;
|
||||
|
||||
@property (nonatomic, assign) CefBrowserImpl *browser;
|
||||
|
||||
@end
|
||||
|
|
|
@ -8,9 +8,12 @@
|
|||
|
||||
#include "browser_impl.h"
|
||||
#include "cef_context.h"
|
||||
#import "web_drag_source_mac.h"
|
||||
#import "web_drop_target_mac.h"
|
||||
#include "webwidget_host.h"
|
||||
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#import "third_party/mozilla/NSPasteboard+Utils.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
|
||||
#include "ui/gfx/rect.h"
|
||||
|
@ -22,13 +25,20 @@
|
|||
- (id)initWithFrame:(NSRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
dropTarget_.reset([[WebDropTarget alloc] initWithWebView:self]);
|
||||
|
||||
// Register the view to handle the appropriate drag types.
|
||||
NSArray* types = [NSArray arrayWithObjects:NSStringPboardType,
|
||||
NSHTMLPboardType, NSURLPboardType, nil];
|
||||
[self registerForDraggedTypes:types];
|
||||
|
||||
trackingArea_ =
|
||||
[[NSTrackingArea alloc] initWithRect:frame
|
||||
options:NSTrackingMouseMoved |
|
||||
NSTrackingActiveInActiveApp |
|
||||
NSTrackingInVisibleRect
|
||||
owner:self
|
||||
userInfo:nil];
|
||||
[[NSTrackingArea alloc] initWithRect:frame
|
||||
options:NSTrackingMouseMoved |
|
||||
NSTrackingActiveInActiveApp |
|
||||
NSTrackingInVisibleRect
|
||||
owner:self
|
||||
userInfo:nil];
|
||||
[self addTrackingArea:trackingArea_];
|
||||
}
|
||||
return self;
|
||||
|
@ -170,9 +180,91 @@
|
|||
|
||||
- (void)setFrame:(NSRect)frameRect {
|
||||
[super setFrame:frameRect];
|
||||
if (browser_ && browser_->UIT_GetWebView())
|
||||
browser_->UIT_GetWebViewHost()->Resize(gfx::Rect(NSRectToCGRect(frameRect)));
|
||||
if (browser_ && browser_->UIT_GetWebView()) {
|
||||
browser_->UIT_GetWebViewHost()->Resize(
|
||||
gfx::Rect(NSRectToCGRect(frameRect)));
|
||||
}
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (void)startDragWithDropData:(const WebDropData&)dropData
|
||||
dragOperationMask:(NSDragOperation)operationMask
|
||||
image:(NSImage*)image
|
||||
offset:(NSPoint)offset {
|
||||
dragSource_.reset([[WebDragSource alloc]
|
||||
initWithWebView:self
|
||||
dropData:&dropData
|
||||
image:image
|
||||
offset:offset
|
||||
pasteboard:[NSPasteboard pasteboardWithName:NSDragPboard]
|
||||
dragOperationMask:operationMask]);
|
||||
[dragSource_ startDrag];
|
||||
}
|
||||
|
||||
// NSPasteboardOwner methods
|
||||
|
||||
- (void)pasteboard:(NSPasteboard*)sender provideDataForType:(NSString*)type {
|
||||
[dragSource_ lazyWriteToPasteboard:sender
|
||||
forType:type];
|
||||
}
|
||||
|
||||
// NSDraggingSource methods
|
||||
|
||||
// Returns what kind of drag operations are available. This is a required
|
||||
// method for NSDraggingSource.
|
||||
- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal {
|
||||
if (dragSource_.get())
|
||||
return [dragSource_ draggingSourceOperationMaskForLocal:isLocal];
|
||||
// No web drag source - this is the case for dragging a file from the
|
||||
// downloads manager. Default to copy operation. Note: It is desirable to
|
||||
// allow the user to either move or copy, but this requires additional
|
||||
// plumbing to update the download item's path once its moved.
|
||||
return NSDragOperationCopy;
|
||||
}
|
||||
|
||||
// Called when a drag initiated in our view ends.
|
||||
- (void)draggedImage:(NSImage*)anImage
|
||||
endedAt:(NSPoint)screenPoint
|
||||
operation:(NSDragOperation)operation {
|
||||
[dragSource_ endDragAt:screenPoint operation:operation];
|
||||
|
||||
// Might as well throw out this object now.
|
||||
dragSource_.reset();
|
||||
}
|
||||
|
||||
// Called when a drag initiated in our view moves.
|
||||
- (void)draggedImage:(NSImage*)draggedImage movedTo:(NSPoint)screenPoint {
|
||||
[dragSource_ moveDragTo:screenPoint];
|
||||
}
|
||||
|
||||
// Called when we're informed where a file should be dropped.
|
||||
- (NSArray*)namesOfPromisedFilesDroppedAtDestination:(NSURL*)dropDest {
|
||||
if (![dropDest isFileURL])
|
||||
return nil;
|
||||
|
||||
NSString* file_name = [dragSource_ dragPromisedFileTo:[dropDest path]];
|
||||
if (!file_name)
|
||||
return nil;
|
||||
|
||||
return [NSArray arrayWithObject:file_name];
|
||||
}
|
||||
|
||||
// NSDraggingDestination methods
|
||||
|
||||
- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender {
|
||||
return [dropTarget_ draggingEntered:sender view:self];
|
||||
}
|
||||
|
||||
- (void)draggingExited:(id<NSDraggingInfo>)sender {
|
||||
[dropTarget_ draggingExited:sender];
|
||||
}
|
||||
|
||||
- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender {
|
||||
return [dropTarget_ draggingUpdated:sender view:self];
|
||||
}
|
||||
|
||||
- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender {
|
||||
return [dropTarget_ performDragOperation:sender view:self];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -3,67 +3,22 @@
|
|||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
#include "include/cef.h"
|
||||
#import "include/cef_application_mac.h"
|
||||
#include "cef_process_ui_thread.h"
|
||||
#include "browser_webkit_glue.h"
|
||||
#include "base/message_pump_mac.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
|
||||
#include "third_party/WebKit/Source/WebKit/mac/WebCoreSupport/WebSystemInterface.h"
|
||||
|
||||
// CrAppProtocol implementation.
|
||||
@interface CrApplication : NSApplication<CrAppProtocol> {
|
||||
@private
|
||||
BOOL handlingSendEvent_;
|
||||
}
|
||||
- (BOOL)isHandlingSendEvent;
|
||||
@end
|
||||
|
||||
@implementation CrApplication
|
||||
- (BOOL)isHandlingSendEvent {
|
||||
return handlingSendEvent_;
|
||||
}
|
||||
|
||||
- (void)sendEvent:(NSEvent*)event {
|
||||
BOOL wasHandlingSendEvent = handlingSendEvent_;
|
||||
handlingSendEvent_ = YES;
|
||||
[super sendEvent:event];
|
||||
handlingSendEvent_ = wasHandlingSendEvent;
|
||||
}
|
||||
@end
|
||||
|
||||
namespace {
|
||||
|
||||
// Memory autorelease pool.
|
||||
static NSAutoreleasePool* g_autopool = nil;
|
||||
|
||||
void RunLoopObserver(CFRunLoopObserverRef observer, CFRunLoopActivity activity,
|
||||
void* info)
|
||||
{
|
||||
CefDoMessageLoopWork();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void CefProcessUIThread::PlatformInit() {
|
||||
// Initialize the CrApplication instance.
|
||||
[CrApplication sharedApplication];
|
||||
g_autopool = [[NSAutoreleasePool alloc] init];
|
||||
// The NSApplication instance must implement the CefAppProtocol protocol.
|
||||
DCHECK([[NSApplication sharedApplication]
|
||||
conformsToProtocol:@protocol(CefAppProtocol)]);
|
||||
|
||||
InitWebCoreSystemInterface();
|
||||
|
||||
// Register the run loop observer.
|
||||
CFRunLoopObserverRef observer =
|
||||
CFRunLoopObserverCreate(NULL,
|
||||
kCFRunLoopBeforeWaiting,
|
||||
YES, /* repeat */
|
||||
0,
|
||||
&RunLoopObserver,
|
||||
NULL);
|
||||
if (observer) {
|
||||
CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer,
|
||||
kCFRunLoopCommonModes);
|
||||
}
|
||||
|
||||
webkit_glue::InitializeDataPak();
|
||||
|
||||
// On Mac, the select popup menus are rendered by the browser.
|
||||
|
@ -71,6 +26,4 @@ void CefProcessUIThread::PlatformInit() {
|
|||
}
|
||||
|
||||
void CefProcessUIThread::PlatformCleanUp() {
|
||||
[g_autopool release];
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,188 @@
|
|||
// 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 "download_util.h"
|
||||
|
||||
#include "base/file_path.h"
|
||||
#include "base/string16.h"
|
||||
#include "base/string_util.h"
|
||||
#include "base/sys_string_conversions.h"
|
||||
#include "base/utf_string_conversions.h"
|
||||
#include "base/threading/thread.h"
|
||||
#include "base/threading/thread_restrictions.h"
|
||||
#include "googleurl/src/gurl.h"
|
||||
#include "net/base/mime_util.h"
|
||||
#include "net/base/net_util.h"
|
||||
|
||||
namespace {
|
||||
|
||||
#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
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace download_util {
|
||||
|
||||
// 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,
|
||||
const std::string& suggested_name,
|
||||
FilePath* generated_name) {
|
||||
string16 new_name = net::GetSuggestedFilename(GURL(url),
|
||||
content_disposition,
|
||||
referrer_charset,
|
||||
suggested_name,
|
||||
ASCIIToUTF16("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 download_util
|
|
@ -0,0 +1,27 @@
|
|||
// 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.
|
||||
|
||||
#ifndef _DOWNLOAD_UTIL_H
|
||||
#define _DOWNLOAD_UTIL_H
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
class GURL;
|
||||
class FilePath;
|
||||
|
||||
namespace download_util {
|
||||
|
||||
// Create a file name based on the response from the server.
|
||||
void GenerateFileName(const GURL& url,
|
||||
const std::string& content_disposition,
|
||||
const std::string& referrer_charset,
|
||||
const std::string& mime_type,
|
||||
const std::string& suggested_name,
|
||||
FilePath* generated_name);
|
||||
|
||||
} // namespace download_util
|
||||
|
||||
#endif // _DOWNLOAD_UTIL_H
|
|
@ -0,0 +1,113 @@
|
|||
// 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 "cef_thread.h"
|
||||
#include "drag_download_util.h"
|
||||
|
||||
#include "base/string_util.h"
|
||||
#include "base/file_path.h"
|
||||
#include "base/file_util.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "base/task.h"
|
||||
#include "base/string_number_conversions.h"
|
||||
#include "base/utf_string_conversions.h"
|
||||
#include "googleurl/src/gurl.h"
|
||||
#include "net/base/file_stream.h"
|
||||
#include "net/base/net_errors.h"
|
||||
|
||||
using net::FileStream;
|
||||
|
||||
namespace drag_download_util {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
FileStream* CreateFileStreamForDrop(FilePath* file_path) {
|
||||
DCHECK(file_path && !file_path->empty());
|
||||
|
||||
scoped_ptr<FileStream> file_stream(new FileStream);
|
||||
const int kMaxSeq = 99;
|
||||
for (int seq = 0; seq <= kMaxSeq; seq++) {
|
||||
FilePath new_file_path;
|
||||
if (seq == 0) {
|
||||
new_file_path = *file_path;
|
||||
} else {
|
||||
#if defined(OS_WIN)
|
||||
string16 suffix = ASCIIToUTF16("-") + base::IntToString16(seq);
|
||||
#else
|
||||
std::string suffix = std::string("-") + base::IntToString(seq);
|
||||
#endif
|
||||
new_file_path = file_path->InsertBeforeExtension(suffix);
|
||||
}
|
||||
|
||||
// Explicitly (and redundantly check) for file -- despite the fact that our
|
||||
// open won't overwrite -- just to avoid log spew.
|
||||
if (!file_util::PathExists(new_file_path) &&
|
||||
file_stream->Open(new_file_path, base::PLATFORM_FILE_CREATE |
|
||||
base::PLATFORM_FILE_WRITE) == net::OK) {
|
||||
*file_path = new_file_path;
|
||||
return file_stream.release();
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PromiseFileFinalizer::PromiseFileFinalizer(
|
||||
DragDownloadFile* drag_file_downloader)
|
||||
: drag_file_downloader_(drag_file_downloader) {
|
||||
}
|
||||
|
||||
PromiseFileFinalizer::~PromiseFileFinalizer() {}
|
||||
|
||||
void PromiseFileFinalizer::Cleanup() {
|
||||
if (drag_file_downloader_.get())
|
||||
drag_file_downloader_ = NULL;
|
||||
}
|
||||
|
||||
void PromiseFileFinalizer::OnDownloadCompleted(const FilePath& file_path) {
|
||||
CefThread::PostTask(
|
||||
CefThread::UI, FROM_HERE,
|
||||
NewRunnableMethod(this, &PromiseFileFinalizer::Cleanup));
|
||||
}
|
||||
|
||||
void PromiseFileFinalizer::OnDownloadAborted() {
|
||||
CefThread::PostTask(
|
||||
CefThread::UI, FROM_HERE,
|
||||
NewRunnableMethod(this, &PromiseFileFinalizer::Cleanup));
|
||||
}
|
||||
|
||||
} // namespace drag_download_util
|
|
@ -0,0 +1,63 @@
|
|||
// 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.
|
||||
|
||||
#ifndef _DRAG_DOWNLOAD_UTIL_H
|
||||
#define _DRAG_DOWNLOAD_UTIL_H
|
||||
#pragma once
|
||||
|
||||
#include "drag_download_file.h"
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/string16.h"
|
||||
#include "ui/base/dragdrop/download_file_interface.h"
|
||||
|
||||
class FilePath;
|
||||
class GURL;
|
||||
namespace net {
|
||||
class FileStream;
|
||||
}
|
||||
|
||||
namespace drag_download_util {
|
||||
|
||||
// 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
|
||||
bool ParseDownloadMetadata(const string16& metadata,
|
||||
string16* mime_type,
|
||||
FilePath* file_name,
|
||||
GURL* url);
|
||||
|
||||
// Create a new file at the specified path. If the file already exists, try to
|
||||
// insert the sequential unifier to produce a new file, like foo-01.txt.
|
||||
// Return a FileStream if successful.
|
||||
net::FileStream* CreateFileStreamForDrop(FilePath* file_path);
|
||||
|
||||
// Implementation of DownloadFileObserver to finalize the download process.
|
||||
class PromiseFileFinalizer : public ui::DownloadFileObserver {
|
||||
public:
|
||||
explicit PromiseFileFinalizer(DragDownloadFile* drag_file_downloader);
|
||||
virtual ~PromiseFileFinalizer();
|
||||
|
||||
// DownloadFileObserver methods.
|
||||
virtual void OnDownloadCompleted(const FilePath& file_path);
|
||||
virtual void OnDownloadAborted();
|
||||
|
||||
private:
|
||||
void Cleanup();
|
||||
|
||||
scoped_refptr<DragDownloadFile> drag_file_downloader_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(PromiseFileFinalizer);
|
||||
};
|
||||
|
||||
} // namespace drag_download_util
|
||||
|
||||
#endif // _DRAG_DOWNLOAD_UTIL_H
|
|
@ -0,0 +1,82 @@
|
|||
// 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.
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include "base/file_path.h"
|
||||
#include "base/memory/scoped_nsobject.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "googleurl/src/gurl.h"
|
||||
#include "ui/gfx/native_widget_types.h"
|
||||
|
||||
struct WebDropData;
|
||||
@class BrowserWebView;
|
||||
|
||||
// A class that handles tracking and event processing for a drag and drop
|
||||
// originating from the content area.
|
||||
@interface WebDragSource : NSObject {
|
||||
@private
|
||||
// Our web view. Weak reference (owns or co-owns us).
|
||||
BrowserWebView* view_;
|
||||
|
||||
// Our drop data. Should only be initialized once.
|
||||
scoped_ptr<WebDropData> dropData_;
|
||||
|
||||
// The image to show as drag image. Can be nil.
|
||||
scoped_nsobject<NSImage> dragImage_;
|
||||
|
||||
// The offset to draw |dragImage_| at.
|
||||
NSPoint imageOffset_;
|
||||
|
||||
// Our pasteboard.
|
||||
scoped_nsobject<NSPasteboard> pasteboard_;
|
||||
|
||||
// A mask of the allowed drag operations.
|
||||
NSDragOperation dragOperationMask_;
|
||||
|
||||
// The file name to be saved to for a drag-out download.
|
||||
FilePath downloadFileName_;
|
||||
|
||||
// The URL to download from for a drag-out download.
|
||||
GURL downloadURL_;
|
||||
}
|
||||
|
||||
// Initialize a WebDragSource object for a drag (originating on the given
|
||||
// BrowserWebView and with the given dropData and pboard). Fill the pasteboard
|
||||
// with data types appropriate for dropData.
|
||||
- (id)initWithWebView:(BrowserWebView*)view
|
||||
dropData:(const WebDropData*)dropData
|
||||
image:(NSImage*)image
|
||||
offset:(NSPoint)offset
|
||||
pasteboard:(NSPasteboard*)pboard
|
||||
dragOperationMask:(NSDragOperation)dragOperationMask;
|
||||
|
||||
// Returns a mask of the allowed drag operations.
|
||||
- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal;
|
||||
|
||||
// Call when asked to do a lazy write to the pasteboard; hook up to
|
||||
// -pasteboard:provideDataForType: (on the BrowserWebView).
|
||||
- (void)lazyWriteToPasteboard:(NSPasteboard*)pboard
|
||||
forType:(NSString*)type;
|
||||
|
||||
// Start the drag (on the originally provided BrowserWebView); can do this right
|
||||
// after -initWithContentsView:....
|
||||
- (void)startDrag;
|
||||
|
||||
// End the drag and clear the pasteboard; hook up to
|
||||
// -draggedImage:endedAt:operation:.
|
||||
- (void)endDragAt:(NSPoint)screenPoint
|
||||
operation:(NSDragOperation)operation;
|
||||
|
||||
// Drag moved; hook up to -draggedImage:movedTo:.
|
||||
- (void)moveDragTo:(NSPoint)screenPoint;
|
||||
|
||||
// Call to drag a promised file to the given path (should be called before
|
||||
// -endDragAt:...); hook up to -namesOfPromisedFilesDroppedAtDestination:.
|
||||
// Returns the file name (not including path) of the file deposited (or which
|
||||
// will be deposited).
|
||||
- (NSString*)dragPromisedFileTo:(NSString*)path;
|
||||
|
||||
@end
|
|
@ -0,0 +1,456 @@
|
|||
// 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 "browser_impl.h"
|
||||
#import "browser_webview_mac.h"
|
||||
#include "drag_download_util.h"
|
||||
#include "download_util.h"
|
||||
#import "web_drag_source_mac.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#include "base/file_path.h"
|
||||
#include "base/string_util.h"
|
||||
#include "base/sys_string_conversions.h"
|
||||
#include "base/task.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/net_util.h"
|
||||
#import "third_party/mozilla/NSPasteboard+Utils.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebPoint.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
|
||||
#include "ui/gfx/mac/nsimage_cache.h"
|
||||
#include "webkit/glue/webdropdata.h"
|
||||
|
||||
using base::SysNSStringToUTF8;
|
||||
using base::SysUTF8ToNSString;
|
||||
using base::SysUTF16ToNSString;
|
||||
using net::FileStream;
|
||||
using WebKit::WebDragOperationNone;
|
||||
using WebKit::WebView;
|
||||
|
||||
namespace {
|
||||
|
||||
// An unofficial standard pasteboard title type to be provided alongside the
|
||||
// |NSURLPboardType|.
|
||||
NSString* const kNSURLTitlePboardType = @"public.url-name";
|
||||
|
||||
// Converts a string16 into a FilePath. Use this method instead of
|
||||
// -[NSString fileSystemRepresentation] to prevent exceptions from being thrown.
|
||||
// See http://crbug.com/78782 for more info.
|
||||
FilePath FilePathFromFilename(const string16& filename) {
|
||||
NSString* str = SysUTF16ToNSString(filename);
|
||||
char buf[MAXPATHLEN];
|
||||
if (![str getFileSystemRepresentation:buf maxLength:sizeof(buf)])
|
||||
return FilePath();
|
||||
return FilePath(buf);
|
||||
}
|
||||
|
||||
// Returns a filename appropriate for the drop data
|
||||
// TODO(viettrungluu): Refactor to make it common across platforms,
|
||||
// and move it somewhere sensible.
|
||||
FilePath GetFileNameFromDragData(const WebDropData& drop_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(FilePathFromFilename(drop_data.file_description_filename));
|
||||
file_name = file_name.BaseName().RemoveExtension();
|
||||
|
||||
if (file_name.empty()) {
|
||||
// Retrieve the name from the URL.
|
||||
string16 suggested_filename =
|
||||
net::GetSuggestedFilename(drop_data.url, "", "", "", string16());
|
||||
file_name = FilePathFromFilename(suggested_filename);
|
||||
}
|
||||
|
||||
file_name = file_name.ReplaceExtension(UTF16ToUTF8(drop_data.file_extension));
|
||||
|
||||
return file_name;
|
||||
}
|
||||
|
||||
// This class's sole task is to write out data for a promised file; the caller
|
||||
// is responsible for opening the file.
|
||||
class PromiseWriterTask : public Task {
|
||||
public:
|
||||
// Assumes ownership of file_stream.
|
||||
PromiseWriterTask(const WebDropData& drop_data,
|
||||
FileStream* file_stream);
|
||||
virtual ~PromiseWriterTask();
|
||||
virtual void Run();
|
||||
|
||||
private:
|
||||
WebDropData drop_data_;
|
||||
|
||||
// This class takes ownership of file_stream_ and will close and delete it.
|
||||
scoped_ptr<FileStream> file_stream_;
|
||||
};
|
||||
|
||||
// Takes the drop data and an open file stream (which it takes ownership of and
|
||||
// will close and delete).
|
||||
PromiseWriterTask::PromiseWriterTask(const WebDropData& drop_data,
|
||||
FileStream* file_stream) :
|
||||
drop_data_(drop_data) {
|
||||
file_stream_.reset(file_stream);
|
||||
DCHECK(file_stream_.get());
|
||||
}
|
||||
|
||||
PromiseWriterTask::~PromiseWriterTask() {
|
||||
DCHECK(file_stream_.get());
|
||||
if (file_stream_.get())
|
||||
file_stream_->Close();
|
||||
}
|
||||
|
||||
void PromiseWriterTask::Run() {
|
||||
CHECK(file_stream_.get());
|
||||
file_stream_->Write(drop_data_.file_contents.data(),
|
||||
drop_data_.file_contents.length(),
|
||||
NULL);
|
||||
|
||||
// Let our destructor take care of business.
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
@interface WebDragSource(Private)
|
||||
|
||||
- (void)fillPasteboard;
|
||||
- (NSImage*)dragImage;
|
||||
|
||||
@end // @interface WebDragSource(Private)
|
||||
|
||||
|
||||
@implementation WebDragSource
|
||||
|
||||
- (id)initWithWebView:(BrowserWebView*)view
|
||||
dropData:(const WebDropData*)dropData
|
||||
image:(NSImage*)image
|
||||
offset:(NSPoint)offset
|
||||
pasteboard:(NSPasteboard*)pboard
|
||||
dragOperationMask:(NSDragOperation)dragOperationMask {
|
||||
if ((self = [super init])) {
|
||||
view_ = view;
|
||||
DCHECK(view_);
|
||||
|
||||
dropData_.reset(new WebDropData(*dropData));
|
||||
DCHECK(dropData_.get());
|
||||
|
||||
dragImage_.reset([image retain]);
|
||||
imageOffset_ = offset;
|
||||
|
||||
pasteboard_.reset([pboard retain]);
|
||||
DCHECK(pasteboard_.get());
|
||||
|
||||
dragOperationMask_ = dragOperationMask;
|
||||
|
||||
[self fillPasteboard];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal {
|
||||
return dragOperationMask_;
|
||||
}
|
||||
|
||||
- (void)lazyWriteToPasteboard:(NSPasteboard*)pboard forType:(NSString*)type {
|
||||
// NSHTMLPboardType requires the character set to be declared. Otherwise, it
|
||||
// assumes US-ASCII. Awesome.
|
||||
static const string16 kHtmlHeader =
|
||||
ASCIIToUTF16("<meta http-equiv=\"Content-Type\" "
|
||||
"content=\"text/html;charset=UTF-8\">");
|
||||
|
||||
// Be extra paranoid; avoid crashing.
|
||||
if (!dropData_.get()) {
|
||||
NOTREACHED() << "No drag-and-drop data available for lazy write.";
|
||||
return;
|
||||
}
|
||||
|
||||
// HTML.
|
||||
if ([type isEqualToString:NSHTMLPboardType]) {
|
||||
DCHECK(!dropData_->text_html.empty());
|
||||
// See comment on |kHtmlHeader| above.
|
||||
[pboard setString:SysUTF16ToNSString(kHtmlHeader + dropData_->text_html)
|
||||
forType:NSHTMLPboardType];
|
||||
|
||||
// URL.
|
||||
} else if ([type isEqualToString:NSURLPboardType]) {
|
||||
DCHECK(dropData_->url.is_valid());
|
||||
NSString* urlStr = SysUTF8ToNSString(dropData_->url.spec());
|
||||
NSURL* url = [NSURL URLWithString:urlStr];
|
||||
// If NSURL creation failed, check for a badly-escaped javascript URL.
|
||||
if (!url && urlStr && dropData_->url.SchemeIs("javascript")) {
|
||||
NSString *escapedStr =
|
||||
[urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
|
||||
url = [NSURL URLWithString:escapedStr];
|
||||
}
|
||||
[url writeToPasteboard:pboard];
|
||||
// URL title.
|
||||
} else if ([type isEqualToString:kNSURLTitlePboardType]) {
|
||||
[pboard setString:SysUTF16ToNSString(dropData_->url_title)
|
||||
forType:kNSURLTitlePboardType];
|
||||
|
||||
// File contents.
|
||||
} else if ([type isEqualToString:NSFileContentsPboardType] ||
|
||||
[type isEqualToString:NSCreateFileContentsPboardType(
|
||||
SysUTF16ToNSString(dropData_->file_extension))]) {
|
||||
// TODO(viettrungluu: find something which is known to accept
|
||||
// NSFileContentsPboardType to check that this actually works!
|
||||
scoped_nsobject<NSFileWrapper> file_wrapper(
|
||||
[[NSFileWrapper alloc] initRegularFileWithContents:[NSData
|
||||
dataWithBytes:dropData_->file_contents.data()
|
||||
length:dropData_->file_contents.length()]]);
|
||||
[file_wrapper setPreferredFilename:SysUTF8ToNSString(
|
||||
GetFileNameFromDragData(*dropData_).value())];
|
||||
[pboard writeFileWrapper:file_wrapper];
|
||||
|
||||
// TIFF.
|
||||
} else if ([type isEqualToString:NSTIFFPboardType]) {
|
||||
// TODO(viettrungluu): This is a bit odd since we rely on Cocoa to render
|
||||
// our image into a TIFF. This is also suboptimal since this is all done
|
||||
// synchronously. I'm not sure there's much we can easily do about it.
|
||||
scoped_nsobject<NSImage> image(
|
||||
[[NSImage alloc] initWithData:[NSData
|
||||
dataWithBytes:dropData_->file_contents.data()
|
||||
length:dropData_->file_contents.length()]]);
|
||||
[pboard setData:[image TIFFRepresentation] forType:NSTIFFPboardType];
|
||||
|
||||
// Plain text.
|
||||
} else if ([type isEqualToString:NSStringPboardType]) {
|
||||
DCHECK(!dropData_->plain_text.empty());
|
||||
[pboard setString:SysUTF16ToNSString(dropData_->plain_text)
|
||||
forType:NSStringPboardType];
|
||||
|
||||
// Oops!
|
||||
} else {
|
||||
NOTREACHED() << "Asked for a drag pasteboard type we didn't offer.";
|
||||
}
|
||||
}
|
||||
|
||||
- (NSPoint)convertScreenPoint:(NSPoint)screenPoint {
|
||||
NSPoint basePoint = [[view_ window] convertScreenToBase:screenPoint];
|
||||
return [view_ convertPoint:basePoint fromView:nil];
|
||||
}
|
||||
|
||||
- (void)startDrag {
|
||||
NSEvent* currentEvent = [NSApp currentEvent];
|
||||
|
||||
// Synthesize an event for dragging, since we can't be sure that
|
||||
// [NSApp currentEvent] will return a valid dragging event.
|
||||
NSWindow* window = [view_ window];
|
||||
NSPoint position = [window mouseLocationOutsideOfEventStream];
|
||||
NSTimeInterval eventTime = [currentEvent timestamp];
|
||||
NSEvent* dragEvent = [NSEvent mouseEventWithType:NSLeftMouseDragged
|
||||
location:position
|
||||
modifierFlags:NSLeftMouseDraggedMask
|
||||
timestamp:eventTime
|
||||
windowNumber:[window windowNumber]
|
||||
context:nil
|
||||
eventNumber:0
|
||||
clickCount:1
|
||||
pressure:1.0];
|
||||
|
||||
if (dragImage_) {
|
||||
position.x -= imageOffset_.x;
|
||||
// Deal with Cocoa's flipped coordinate system.
|
||||
position.y -= [dragImage_.get() size].height - imageOffset_.y;
|
||||
}
|
||||
// Per kwebster, offset arg is ignored, see -_web_DragImageForElement: in
|
||||
// third_party/WebKit/Source/WebKit/mac/Misc/WebNSViewExtras.m.
|
||||
[window dragImage:[self dragImage]
|
||||
at:position
|
||||
offset:NSZeroSize
|
||||
event:dragEvent
|
||||
pasteboard:pasteboard_
|
||||
source:view_
|
||||
slideBack:YES];
|
||||
}
|
||||
|
||||
- (void)endDragAt:(NSPoint)screenPoint
|
||||
operation:(NSDragOperation)operation {
|
||||
// Convert |screenPoint| to view coordinates and flip it.
|
||||
NSWindow* window = [view_ window];
|
||||
NSPoint localPoint = [self convertScreenPoint:screenPoint];
|
||||
NSRect viewFrame = [window frame];
|
||||
localPoint.y = viewFrame.size.height - localPoint.y;
|
||||
// Flip |screenPoint|.
|
||||
NSRect screenFrame = [[window screen] frame];
|
||||
screenPoint.y = screenFrame.size.height - screenPoint.y;
|
||||
|
||||
// If AppKit returns a copy and move operation, mask off the move bit
|
||||
// because WebCore does not understand what it means to do both, which
|
||||
// results in an assertion failure/renderer crash.
|
||||
if (operation == (NSDragOperationMove | NSDragOperationCopy))
|
||||
operation &= ~NSDragOperationMove;
|
||||
|
||||
// TODO: Figure out why |operation| is always NSDragOperationNone.
|
||||
if (operation == NSDragOperationNone)
|
||||
operation = NSDragOperationCopy;
|
||||
|
||||
WebView* webview = view_.browser->UIT_GetWebView();
|
||||
|
||||
gfx::Point client(localPoint.x, localPoint.y);
|
||||
gfx::Point screen(screenPoint.x, screenPoint.y);
|
||||
webview->dragSourceEndedAt(client, screen,
|
||||
static_cast<WebKit::WebDragOperation>(operation));
|
||||
|
||||
// Make sure the pasteboard owner isn't us.
|
||||
[pasteboard_ declareTypes:[NSArray array] owner:nil];
|
||||
|
||||
webview->dragSourceSystemDragEnded();
|
||||
}
|
||||
|
||||
- (void)moveDragTo:(NSPoint)screenPoint {
|
||||
// Convert |screenPoint| to view coordinates and flip it.
|
||||
NSWindow* window = [view_ window];
|
||||
NSPoint localPoint = [self convertScreenPoint:screenPoint];
|
||||
NSRect viewFrame = [window frame];
|
||||
localPoint.y = viewFrame.size.height - localPoint.y;
|
||||
// Flip |screenPoint|.
|
||||
NSRect screenFrame = [[window screen] frame];
|
||||
screenPoint.y = screenFrame.size.height - screenPoint.y;
|
||||
|
||||
WebView* webview = view_.browser->UIT_GetWebView();
|
||||
|
||||
gfx::Point client(localPoint.x, localPoint.y);
|
||||
gfx::Point screen(screenPoint.x, screenPoint.y);
|
||||
webview->dragSourceMovedTo(client, screen, WebDragOperationNone);
|
||||
}
|
||||
|
||||
- (NSString*)dragPromisedFileTo:(NSString*)path {
|
||||
// Be extra paranoid; avoid crashing.
|
||||
if (!dropData_.get()) {
|
||||
NOTREACHED() << "No drag-and-drop data available for promised file.";
|
||||
return nil;
|
||||
}
|
||||
|
||||
FilePath fileName = downloadFileName_.empty() ?
|
||||
GetFileNameFromDragData(*dropData_) : downloadFileName_;
|
||||
FilePath filePath(SysNSStringToUTF8(path));
|
||||
filePath = filePath.Append(fileName);
|
||||
|
||||
// CreateFileStreamForDrop() will call file_util::PathExists(),
|
||||
// which is blocking. Since this operation is already blocking the
|
||||
// UI thread on OSX, it should be reasonable to let it happen.
|
||||
base::ThreadRestrictions::ScopedAllowIO allowIO;
|
||||
FileStream* fileStream =
|
||||
drag_download_util::CreateFileStreamForDrop(&filePath);
|
||||
if (!fileStream)
|
||||
return nil;
|
||||
|
||||
if (downloadURL_.is_valid()) {
|
||||
WebView* webview = view_.browser->UIT_GetWebView();
|
||||
const GURL& page_url = webview->mainFrame()->document().url();
|
||||
const std::string& page_encoding =
|
||||
webview->mainFrame()->document().encoding().utf8();
|
||||
|
||||
scoped_refptr<DragDownloadFile> dragFileDownloader(new DragDownloadFile(
|
||||
filePath,
|
||||
linked_ptr<net::FileStream>(fileStream),
|
||||
downloadURL_,
|
||||
page_url,
|
||||
page_encoding,
|
||||
view_.browser->UIT_GetWebViewDelegate()));
|
||||
|
||||
// The finalizer will take care of closing and deletion.
|
||||
dragFileDownloader->Start(
|
||||
new drag_download_util::PromiseFileFinalizer(dragFileDownloader));
|
||||
} else {
|
||||
// The writer will take care of closing and deletion.
|
||||
CefThread::PostTask(CefThread::FILE, FROM_HERE,
|
||||
new PromiseWriterTask(*dropData_, fileStream));
|
||||
}
|
||||
|
||||
// Once we've created the file, we should return the file name.
|
||||
return SysUTF8ToNSString(filePath.BaseName().value());
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end // @implementation WebDragSource
|
||||
|
||||
|
||||
@implementation WebDragSource (Private)
|
||||
|
||||
- (void)fillPasteboard {
|
||||
DCHECK(pasteboard_.get());
|
||||
|
||||
[pasteboard_ declareTypes:[NSArray array] owner:view_];
|
||||
|
||||
// HTML.
|
||||
if (!dropData_->text_html.empty())
|
||||
[pasteboard_ addTypes:[NSArray arrayWithObject:NSHTMLPboardType]
|
||||
owner:view_];
|
||||
|
||||
// URL (and title).
|
||||
if (dropData_->url.is_valid())
|
||||
[pasteboard_ addTypes:[NSArray arrayWithObjects:NSURLPboardType,
|
||||
kNSURLTitlePboardType, nil]
|
||||
owner:view_];
|
||||
|
||||
// File.
|
||||
if (!dropData_->file_contents.empty() ||
|
||||
!dropData_->download_metadata.empty()) {
|
||||
NSString* fileExtension = 0;
|
||||
|
||||
if (dropData_->download_metadata.empty()) {
|
||||
// |dropData_->file_extension| comes with the '.', which we must strip.
|
||||
fileExtension = (dropData_->file_extension.length() > 0) ?
|
||||
SysUTF16ToNSString(dropData_->file_extension.substr(1)) : @"";
|
||||
} else {
|
||||
string16 mimeType;
|
||||
FilePath fileName;
|
||||
if (drag_download_util::ParseDownloadMetadata(
|
||||
dropData_->download_metadata,
|
||||
&mimeType,
|
||||
&fileName,
|
||||
&downloadURL_)) {
|
||||
download_util::GenerateFileName(
|
||||
downloadURL_,
|
||||
std::string(),
|
||||
std::string(),
|
||||
UTF16ToUTF8(mimeType),
|
||||
fileName.value(),
|
||||
&downloadFileName_);
|
||||
fileExtension = SysUTF8ToNSString(downloadFileName_.Extension());
|
||||
}
|
||||
}
|
||||
|
||||
if (fileExtension) {
|
||||
// File contents (with and without specific type), file (HFS) promise,
|
||||
// TIFF.
|
||||
// TODO(viettrungluu): others?
|
||||
[pasteboard_ addTypes:[NSArray arrayWithObjects:
|
||||
NSFileContentsPboardType,
|
||||
NSCreateFileContentsPboardType(fileExtension),
|
||||
NSFilesPromisePboardType,
|
||||
NSTIFFPboardType,
|
||||
nil]
|
||||
owner:view_];
|
||||
|
||||
// For the file promise, we need to specify the extension.
|
||||
[pasteboard_ setPropertyList:[NSArray arrayWithObject:fileExtension]
|
||||
forType:NSFilesPromisePboardType];
|
||||
}
|
||||
}
|
||||
|
||||
// Plain text.
|
||||
if (!dropData_->plain_text.empty())
|
||||
[pasteboard_ addTypes:[NSArray arrayWithObject:NSStringPboardType]
|
||||
owner:view_];
|
||||
}
|
||||
|
||||
- (NSImage*)dragImage {
|
||||
if (dragImage_)
|
||||
return dragImage_;
|
||||
|
||||
// Default to returning a generic image.
|
||||
return gfx::GetCachedImageWithName(@"nav.pdf");
|
||||
}
|
||||
|
||||
@end // @implementation WebDragSource (Private)
|
|
@ -0,0 +1,37 @@
|
|||
// 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.
|
||||
|
||||
#ifndef _WEB_DRAG_UTILS_MAC
|
||||
#define _WEB_DRAG_UTILS_MAC
|
||||
#pragma once
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "googleurl/src/gurl.h"
|
||||
|
||||
namespace drag_util {
|
||||
|
||||
// Populates the |url| and |title| with URL data in |pboard|. There may be more
|
||||
// than one, but we only handle dropping the first. |url| must not be |NULL|;
|
||||
// |title| is an optional parameter. Returns |YES| if URL data was obtained from
|
||||
// the pasteboard, |NO| otherwise. If |convert_filenames| is |YES|, the function
|
||||
// will also attempt to convert filenames in |pboard| to file URLs.
|
||||
BOOL PopulateURLAndTitleFromPasteBoard(GURL* url,
|
||||
string16* title,
|
||||
NSPasteboard* pboard,
|
||||
BOOL convert_filenames);
|
||||
|
||||
// Returns the first file URL from |info|, if there is one. If |info| doesn't
|
||||
// contain any file URLs, an empty |GURL| is returned.
|
||||
GURL GetFileURLFromDropData(id<NSDraggingInfo> info);
|
||||
|
||||
// Determines whether the given drag and drop operation contains content that
|
||||
// is supported by the web view. In particular, if the content is a local file
|
||||
// URL, this checks if it is of a type that can be shown in the tab contents.
|
||||
BOOL IsUnsupportedDropData(id<NSDraggingInfo> info);
|
||||
|
||||
} // namespace drag_util
|
||||
|
||||
#endif // _WEB_DRAG_UTILS_MAC
|
|
@ -0,0 +1,101 @@
|
|||
// 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.
|
||||
|
||||
#import "web_drag_utils_mac.h"
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/sys_string_conversions.h"
|
||||
#include "googleurl/src/gurl.h"
|
||||
#include "net/base/mime_util.h"
|
||||
#include "net/base/net_util.h"
|
||||
#import "third_party/mozilla/NSPasteboard+Utils.h"
|
||||
#include "webkit/plugins/npapi/plugin_list.h"
|
||||
|
||||
namespace drag_util {
|
||||
|
||||
BOOL PopulateURLAndTitleFromPasteBoard(GURL* url,
|
||||
string16* title,
|
||||
NSPasteboard* pboard,
|
||||
BOOL convert_filenames) {
|
||||
CHECK(url);
|
||||
|
||||
// Bail out early if there's no URL data.
|
||||
if (![pboard containsURLData])
|
||||
return NO;
|
||||
|
||||
// -getURLs:andTitles:convertingFilenames: will already validate URIs so we
|
||||
// don't need to again. The arrays returned are both of NSStrings.
|
||||
NSArray* url_array = nil;
|
||||
NSArray* title_array = nil;
|
||||
[pboard getURLs:&url_array andTitles:&title_array
|
||||
convertingFilenames:convert_filenames];
|
||||
DCHECK_EQ([url_array count], [title_array count]);
|
||||
// It's possible that no URLs were actually provided!
|
||||
if (![url_array count])
|
||||
return NO;
|
||||
NSString* url_string = [url_array objectAtIndex:0];
|
||||
if ([url_string length]) {
|
||||
// Check again just to make sure to not assign NULL into a std::string,
|
||||
// which throws an exception.
|
||||
const char* utf8_url = [url_string UTF8String];
|
||||
if (utf8_url) {
|
||||
*url = GURL(utf8_url);
|
||||
// Extra paranoia check.
|
||||
if (title && [title_array count])
|
||||
*title = base::SysNSStringToUTF16([title_array objectAtIndex:0]);
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
GURL GetFileURLFromDropData(id<NSDraggingInfo> info) {
|
||||
if ([[info draggingPasteboard] containsURLData]) {
|
||||
GURL url;
|
||||
PopulateURLAndTitleFromPasteBoard(&url,
|
||||
NULL,
|
||||
[info draggingPasteboard],
|
||||
YES);
|
||||
|
||||
if (url.SchemeIs("file"))
|
||||
return url;
|
||||
}
|
||||
return GURL();
|
||||
}
|
||||
|
||||
static BOOL IsSupportedFileURL(const GURL& url) {
|
||||
FilePath full_path;
|
||||
net::FileURLToFilePath(url, &full_path);
|
||||
|
||||
std::string mime_type;
|
||||
net::GetMimeTypeFromFile(full_path, &mime_type);
|
||||
|
||||
// This logic mirrors |BufferedResourceHandler::ShouldDownload()|.
|
||||
// TODO(asvitkine): Refactor this out to a common location instead of
|
||||
// duplicating code.
|
||||
if (net::IsSupportedMimeType(mime_type))
|
||||
return YES;
|
||||
|
||||
// Check whether there is a plugin that supports the mime type. (e.g. PDF)
|
||||
webkit::npapi::PluginList* list = webkit::npapi::PluginList::Singleton();
|
||||
webkit::npapi::WebPluginInfo info;
|
||||
if (list->PluginsLoaded() &&
|
||||
list->GetPluginInfo(GURL(), mime_type, false, &info, NULL)) {
|
||||
return webkit::npapi::IsPluginEnabled(info);
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
BOOL IsUnsupportedDropData(id<NSDraggingInfo> info) {
|
||||
GURL url = GetFileURLFromDropData(info);
|
||||
if (!url.is_empty()) {
|
||||
// If dragging a file, only allow dropping supported file types (that the
|
||||
// web view can display).
|
||||
return !IsSupportedFileURL(url);
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
} // namespace drag_util
|
|
@ -0,0 +1,69 @@
|
|||
// 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.
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include "base/string16.h"
|
||||
|
||||
class GURL;
|
||||
struct WebDropData;
|
||||
@class BrowserWebView;
|
||||
class WebViewHost;
|
||||
|
||||
// A class that handles tracking and event processing for a drag and drop
|
||||
// over the content area. Assumes something else initiates the drag, this is
|
||||
// only for processing during a drag.
|
||||
|
||||
@interface WebDropTarget : NSObject {
|
||||
@private
|
||||
// Our associated WebView. Weak reference.
|
||||
BrowserWebView* view_;
|
||||
|
||||
// Updated asynchronously during a drag to tell us whether or not we should
|
||||
// allow the drop.
|
||||
NSDragOperation current_operation_;
|
||||
|
||||
// Keep track of the WebViewHost we're dragging over. If it changes during a
|
||||
// drag, we need to re-send the DragEnter message.
|
||||
WebViewHost* current_wvh_;
|
||||
}
|
||||
|
||||
// |view| is the WebView representing this browser window, used to communicate
|
||||
// drag&drop messages to WebCore and handle navigation on a successful drop
|
||||
// (if necessary).
|
||||
- (id)initWithWebView:(BrowserWebView*)view;
|
||||
|
||||
// Sets the current operation negotiated by the source and destination,
|
||||
// which determines whether or not we should allow the drop. Takes effect the
|
||||
// next time |-draggingUpdated:| is called.
|
||||
- (void)setCurrentOperation: (NSDragOperation)operation;
|
||||
|
||||
// Messages to send during the tracking of a drag, ususally upon receiving
|
||||
// calls from the view system. Communicates the drag messages to WebCore.
|
||||
- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info
|
||||
view:(NSView*)view;
|
||||
- (void)draggingExited:(id<NSDraggingInfo>)info;
|
||||
- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)info
|
||||
view:(NSView*)view;
|
||||
- (BOOL)performDragOperation:(id<NSDraggingInfo>)info
|
||||
view:(NSView*)view;
|
||||
|
||||
@end
|
||||
|
||||
// Public use only for unit tests.
|
||||
@interface WebDropTarget(Testing)
|
||||
// Given |data|, which should not be nil, fill it in using the contents of the
|
||||
// given pasteboard.
|
||||
- (void)populateWebDropData:(WebDropData*)data
|
||||
fromPasteboard:(NSPasteboard*)pboard;
|
||||
// Given a point in window coordinates and a view in that window, return a
|
||||
// flipped point in the coordinate system of |view|.
|
||||
- (NSPoint)flipWindowPointToView:(const NSPoint&)windowPoint
|
||||
view:(NSView*)view;
|
||||
// Given a point in window coordinates and a view in that window, return a
|
||||
// flipped point in screen coordinates.
|
||||
- (NSPoint)flipWindowPointToScreen:(const NSPoint&)windowPoint
|
||||
view:(NSView*)view;
|
||||
@end
|
|
@ -0,0 +1,234 @@
|
|||
// 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 "browser_impl.h"
|
||||
#import "browser_webview_mac.h"
|
||||
#include "cef_context.h"
|
||||
#import "web_drop_target_mac.h"
|
||||
#import "web_drag_utils_mac.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/sys_string_conversions.h"
|
||||
#import "third_party/mozilla/NSPasteboard+Utils.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDragData.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDragOperation.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"
|
||||
#include "webkit/glue/window_open_disposition.h"
|
||||
|
||||
using WebKit::WebDragOperationsMask;
|
||||
using WebKit::WebPoint;
|
||||
using WebKit::WebView;
|
||||
|
||||
@implementation WebDropTarget
|
||||
|
||||
// |view| is the WebView representing this browser window, used to communicate
|
||||
// drag&drop messages to WebCore and handle navigation on a successful drop
|
||||
// (if necessary).
|
||||
- (id)initWithWebView:(BrowserWebView*)view {
|
||||
if ((self = [super init]))
|
||||
view_ = view;
|
||||
return self;
|
||||
}
|
||||
|
||||
// Call to set whether or not we should allow the drop. Takes effect the
|
||||
// next time |-draggingUpdated:| is called.
|
||||
- (void)setCurrentOperation: (NSDragOperation)operation {
|
||||
current_operation_ = operation;
|
||||
}
|
||||
|
||||
// Given a point in window coordinates and a view in that window, return a
|
||||
// flipped point in the coordinate system of |view|.
|
||||
- (NSPoint)flipWindowPointToView:(const NSPoint&)windowPoint
|
||||
view:(NSView*)view {
|
||||
DCHECK(view);
|
||||
NSPoint viewPoint = [view convertPoint:windowPoint fromView:nil];
|
||||
NSRect viewFrame = [view frame];
|
||||
viewPoint.y = viewFrame.size.height - viewPoint.y;
|
||||
return viewPoint;
|
||||
}
|
||||
|
||||
// Given a point in window coordinates and a view in that window, return a
|
||||
// flipped point in screen coordinates.
|
||||
- (NSPoint)flipWindowPointToScreen:(const NSPoint&)windowPoint
|
||||
view:(NSView*)view {
|
||||
DCHECK(view);
|
||||
NSPoint screenPoint = [[view window] convertBaseToScreen:windowPoint];
|
||||
NSScreen* screen = [[view window] screen];
|
||||
NSRect screenFrame = [screen frame];
|
||||
screenPoint.y = screenFrame.size.height - screenPoint.y;
|
||||
return screenPoint;
|
||||
}
|
||||
|
||||
// Return YES if the drop site only allows drops that would navigate. If this
|
||||
// is the case, we don't want to pass messages to the renderer because there's
|
||||
// really no point (i.e., there's nothing that cares about the mouse position or
|
||||
// entering and exiting). One example is an interstitial page (e.g., safe
|
||||
// browsing warning).
|
||||
- (BOOL)onlyAllowsNavigation {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Messages to send during the tracking of a drag, usually upon receiving
|
||||
// calls from the view system. Communicates the drag messages to WebCore.
|
||||
|
||||
- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info
|
||||
view:(NSView*)view {
|
||||
// Save off the current WebViewHost so we can tell if it changes during a
|
||||
// drag. If it does, we need to send a new enter message in draggingUpdated:.
|
||||
current_wvh_ = _Context->current_webviewhost();
|
||||
DCHECK(current_wvh_);
|
||||
|
||||
if ([self onlyAllowsNavigation]) {
|
||||
if ([[info draggingPasteboard] containsURLData])
|
||||
return NSDragOperationCopy;
|
||||
return NSDragOperationNone;
|
||||
}
|
||||
|
||||
WebView* webview = view_.browser->UIT_GetWebView();
|
||||
|
||||
// Fill out a WebDropData from pasteboard.
|
||||
WebDropData data;
|
||||
[self populateWebDropData:&data fromPasteboard:[info draggingPasteboard]];
|
||||
|
||||
// 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];
|
||||
webview->dragTargetDragEnter(data.ToDragData(),
|
||||
WebPoint(viewPoint.x, viewPoint.y),
|
||||
WebPoint(screenPoint.x, screenPoint.y),
|
||||
static_cast<WebDragOperationsMask>(mask));
|
||||
|
||||
// We won't know the true operation (whether the drag is allowed) until we
|
||||
// hear back from the renderer. For now, be optimistic:
|
||||
current_operation_ = NSDragOperationCopy;
|
||||
return current_operation_;
|
||||
}
|
||||
|
||||
- (void)draggingExited:(id<NSDraggingInfo>)info {
|
||||
DCHECK(current_wvh_);
|
||||
if (current_wvh_ != _Context->current_webviewhost())
|
||||
return;
|
||||
|
||||
WebView* webview = view_.browser->UIT_GetWebView();
|
||||
|
||||
// Nothing to do in the interstitial case.
|
||||
|
||||
webview->dragTargetDragLeave();
|
||||
}
|
||||
|
||||
- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)info
|
||||
view:(NSView*)view {
|
||||
DCHECK(current_wvh_);
|
||||
if (current_wvh_ != _Context->current_webviewhost())
|
||||
[self draggingEntered:info view:view];
|
||||
|
||||
if ([self onlyAllowsNavigation]) {
|
||||
if ([[info draggingPasteboard] containsURLData])
|
||||
return NSDragOperationCopy;
|
||||
return NSDragOperationNone;
|
||||
}
|
||||
|
||||
WebView* webview = view_.browser->UIT_GetWebView();
|
||||
|
||||
// Create the appropriate mouse locations for WebCore. The draggingLocation
|
||||
// is in window coordinates.
|
||||
NSPoint windowPoint = [info draggingLocation];
|
||||
NSPoint viewPoint = [self flipWindowPointToView:windowPoint view:view];
|
||||
NSPoint screenPoint = [self flipWindowPointToScreen:windowPoint view:view];
|
||||
NSDragOperation mask = [info draggingSourceOperationMask];
|
||||
webview->dragTargetDragOver(WebPoint(viewPoint.x, viewPoint.y),
|
||||
WebPoint(screenPoint.x, screenPoint.y),
|
||||
static_cast<WebDragOperationsMask>(mask));
|
||||
|
||||
return current_operation_;
|
||||
}
|
||||
|
||||
- (BOOL)performDragOperation:(id<NSDraggingInfo>)info
|
||||
view:(NSView*)view {
|
||||
DCHECK(current_wvh_);
|
||||
if (current_wvh_ != _Context->current_webviewhost())
|
||||
[self draggingEntered:info view:view];
|
||||
|
||||
// Check if we only allow navigation and navigate to a url on the pasteboard.
|
||||
if ([self onlyAllowsNavigation]) {
|
||||
NSPasteboard* pboard = [info draggingPasteboard];
|
||||
if ([pboard containsURLData]) {
|
||||
GURL url;
|
||||
drag_util::PopulateURLAndTitleFromPasteBoard(&url, NULL, pboard, YES);
|
||||
view_.browser->GetMainFrame()->LoadURL(url.spec());
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
current_wvh_ = NULL;
|
||||
|
||||
WebView* webview = view_.browser->UIT_GetWebView();
|
||||
|
||||
// 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];
|
||||
webview->dragTargetDrop(gfx::Point(viewPoint.x, viewPoint.y),
|
||||
gfx::Point(screenPoint.x, screenPoint.y));
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
// Given |data|, which should not be nil, fill it in using the contents of the
|
||||
// given pasteboard.
|
||||
- (void)populateWebDropData:(WebDropData*)data
|
||||
fromPasteboard:(NSPasteboard*)pboard {
|
||||
DCHECK(data);
|
||||
DCHECK(pboard);
|
||||
NSArray* types = [pboard types];
|
||||
|
||||
// Get URL if possible. To avoid exposing file system paths to web content,
|
||||
// filenames in the drag are not converted to file URLs.
|
||||
drag_util::PopulateURLAndTitleFromPasteBoard(&data->url,
|
||||
&data->url_title,
|
||||
pboard,
|
||||
NO);
|
||||
|
||||
// Get plain text.
|
||||
if ([types containsObject:NSStringPboardType]) {
|
||||
data->plain_text =
|
||||
base::SysNSStringToUTF16([pboard stringForType:NSStringPboardType]);
|
||||
}
|
||||
|
||||
// Get HTML. If there's no HTML, try RTF.
|
||||
if ([types containsObject:NSHTMLPboardType]) {
|
||||
data->text_html =
|
||||
base::SysNSStringToUTF16([pboard stringForType:NSHTMLPboardType]);
|
||||
} else if ([types containsObject:NSRTFPboardType]) {
|
||||
NSString* html = [pboard htmlFromRtf];
|
||||
data->text_html = base::SysNSStringToUTF16(html);
|
||||
}
|
||||
|
||||
// Get files.
|
||||
if ([types containsObject:NSFilenamesPboardType]) {
|
||||
NSArray* files = [pboard propertyListForType:NSFilenamesPboardType];
|
||||
if ([files isKindOfClass:[NSArray class]] && [files count]) {
|
||||
for (NSUInteger i = 0; i < [files count]; i++) {
|
||||
NSString* filename = [files objectAtIndex:i];
|
||||
BOOL isDir = NO;
|
||||
BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:filename
|
||||
isDirectory:&isDir];
|
||||
if (exists && !isDir)
|
||||
data->filenames.push_back(base::SysNSStringToUTF16(filename));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(pinkerton): Get file contents. http://crbug.com/34661
|
||||
}
|
||||
|
||||
@end
|
|
@ -50,6 +50,8 @@ class WebViewHost : public WebWidgetHost {
|
|||
}
|
||||
#elif defined(OS_MACOSX)
|
||||
void SetIsActive(bool active);
|
||||
virtual void MouseEvent(NSEvent *);
|
||||
virtual void SetFocus(bool enable);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "webview_host.h"
|
||||
#include "browser_webview_delegate.h"
|
||||
#include "browser_webview_mac.h"
|
||||
#include "cef_context.h"
|
||||
|
||||
#include "skia/ext/platform_canvas.h"
|
||||
#include "third_party/WebKit/Source/WebKit/chromium/public/WebSize.h"
|
||||
|
@ -56,3 +57,17 @@ WebView* WebViewHost::webview() const {
|
|||
void WebViewHost::SetIsActive(bool active) {
|
||||
webview()->setIsActive(active);
|
||||
}
|
||||
|
||||
void WebViewHost::MouseEvent(NSEvent* event) {
|
||||
_Context->set_current_webviewhost(this);
|
||||
WebWidgetHost::MouseEvent(event);
|
||||
}
|
||||
|
||||
void WebViewHost::SetFocus(bool enable) {
|
||||
if (enable) {
|
||||
// Set the current WebViewHost in case a drag action is started before mouse
|
||||
// events are detected for the window.
|
||||
_Context->set_current_webviewhost(this);
|
||||
}
|
||||
WebWidgetHost::SetFocus(enable);
|
||||
}
|
||||
|
|
|
@ -151,10 +151,10 @@ class WebWidgetHost {
|
|||
// These need to be called from a non-subclass, so they need to be public.
|
||||
public:
|
||||
void Resize(const gfx::Rect& rect);
|
||||
void MouseEvent(NSEvent *);
|
||||
virtual void MouseEvent(NSEvent *);
|
||||
void WheelEvent(NSEvent *);
|
||||
void KeyEvent(NSEvent *);
|
||||
void SetFocus(bool enable);
|
||||
virtual void SetFocus(bool enable);
|
||||
protected:
|
||||
#elif defined(TOOLKIT_USES_GTK)
|
||||
public:
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
// found in the LICENSE file.
|
||||
|
||||
#include "include/cef.h"
|
||||
#import "include/cef_application_mac.h"
|
||||
#include "cefclient.h"
|
||||
#include "binding_test.h"
|
||||
#include "client_handler.h"
|
||||
|
@ -29,6 +30,31 @@ char szWorkingDir[512]; // The current working directory
|
|||
const int kWindowWidth = 800;
|
||||
const int kWindowHeight = 600;
|
||||
|
||||
// Memory AutoRelease pool.
|
||||
static NSAutoreleasePool* g_autopool = nil;
|
||||
|
||||
// Provide the CefAppProtocol implementation required by CEF.
|
||||
@interface ClientApplication : NSApplication<CefAppProtocol> {
|
||||
@private
|
||||
BOOL handlingSendEvent_;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation ClientApplication
|
||||
- (BOOL)isHandlingSendEvent {
|
||||
return handlingSendEvent_;
|
||||
}
|
||||
|
||||
- (void)setHandlingSendEvent:(BOOL)handlingSendEvent {
|
||||
handlingSendEvent_ = handlingSendEvent;
|
||||
}
|
||||
|
||||
- (void)sendEvent:(NSEvent*)event {
|
||||
CefScopedSendingEvent sendingEventScoper;
|
||||
[super sendEvent:event];
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
// Receives notifications from controls and the browser window. Will delete
|
||||
// itself when done.
|
||||
|
@ -174,6 +200,7 @@ NSButton* MakeButton(NSRect* rect, NSString* title, NSView* parent) {
|
|||
- (IBAction)testAcceleratedLayers:(id)sender;
|
||||
- (IBAction)testWebGL:(id)sender;
|
||||
- (IBAction)testHTML5Video:(id)sender;
|
||||
- (IBAction)testDragDrop:(id)sender;
|
||||
- (IBAction)testZoomIn:(id)sender;
|
||||
- (IBAction)testZoomOut:(id)sender;
|
||||
- (IBAction)testZoomReset:(id)sender;
|
||||
|
@ -243,6 +270,9 @@ NSButton* MakeButton(NSRect* rect, NSString* title, NSView* parent) {
|
|||
[testMenu addItemWithTitle:@"HTML5 Video"
|
||||
action:@selector(testHTML5Video:)
|
||||
keyEquivalent:@""];
|
||||
[testMenu addItemWithTitle:@"Drag & Drop"
|
||||
action:@selector(testDragDrop:)
|
||||
keyEquivalent:@""];
|
||||
[testMenu addItemWithTitle:@"Zoom In"
|
||||
action:@selector(testZoomIn:)
|
||||
keyEquivalent:@""];
|
||||
|
@ -419,6 +449,11 @@ NSButton* MakeButton(NSRect* rect, NSString* title, NSView* parent) {
|
|||
RunHTML5VideoTest(g_handler->GetBrowser());
|
||||
}
|
||||
|
||||
- (IBAction)testDragDrop:(id)sender {
|
||||
if(g_handler.get() && g_handler->GetBrowserHwnd())
|
||||
RunDragDropTest(g_handler->GetBrowser());
|
||||
}
|
||||
|
||||
- (IBAction)testZoomIn:(id)sender {
|
||||
if(g_handler.get() && g_handler->GetBrowserHwnd()) {
|
||||
CefRefPtr<CefBrowser> browser = g_handler->GetBrowser();
|
||||
|
@ -448,6 +483,9 @@ NSButton* MakeButton(NSRect* rect, NSString* title, NSView* parent) {
|
|||
CefShutdown();
|
||||
|
||||
[self release];
|
||||
|
||||
// Release the AutoRelease pool.
|
||||
[g_autopool release];
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -458,7 +496,13 @@ int main(int argc, char* argv[])
|
|||
// Retrieve the current working directory.
|
||||
getcwd(szWorkingDir, sizeof(szWorkingDir));
|
||||
|
||||
// Initialize CEF. This will also create the NSApplication instance.
|
||||
// Initialize the AutoRelease pool.
|
||||
g_autopool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
// Initialize the ClientApplication instance.
|
||||
[ClientApplication sharedApplication];
|
||||
|
||||
// Initialize CEF.
|
||||
CefSettings settings;
|
||||
CefInitialize(settings);
|
||||
|
||||
|
@ -472,7 +516,7 @@ int main(int argc, char* argv[])
|
|||
waitUntilDone:NO];
|
||||
|
||||
// Run the application message loop.
|
||||
[NSApp run];
|
||||
CefRunMessageLoop();
|
||||
|
||||
// Don't put anything below this line because it won't be executed.
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue