Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2264)

Unified Diff: app/os_exchange_data_provider_win.cc

Issue 351029: Support dragging a virtual file out of the browser. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 12 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « app/os_exchange_data_provider_win.h ('k') | app/os_exchange_data_win_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: app/os_exchange_data_provider_win.cc
===================================================================
--- app/os_exchange_data_provider_win.cc (revision 35459)
+++ app/os_exchange_data_provider_win.cc (working copy)
@@ -29,6 +29,8 @@
static void CreateValidFileNameFromTitle(const GURL& url,
const std::wstring& title,
std::wstring* validated);
+// Creates a new STGMEDIUM object to hold a file.
+static STGMEDIUM* GetStorageForFileName(const std::wstring& full_path);
// Creates a File Descriptor for the creation of a file to the given URL and
// returns a handle to it.
static STGMEDIUM* GetStorageForFileDescriptor(
@@ -226,12 +228,26 @@
}
// static
+DataObjectImpl* OSExchangeDataProviderWin::GetDataObjectImpl(
+ const OSExchangeData& data) {
+ return static_cast<const OSExchangeDataProviderWin*>(&data.provider())->
+ data_.get();
+}
+
+// static
IDataObject* OSExchangeDataProviderWin::GetIDataObject(
const OSExchangeData& data) {
- return static_cast<const OSExchangeDataProviderWin&>(data.provider()).
+ return static_cast<const OSExchangeDataProviderWin*>(&data.provider())->
data_object();
}
+// static
+IAsyncOperation* OSExchangeDataProviderWin::GetIAsyncOperation(
+ const OSExchangeData& data) {
+ return static_cast<const OSExchangeDataProviderWin*>(&data.provider())->
+ async_operation();
+}
+
OSExchangeDataProviderWin::OSExchangeDataProviderWin(IDataObject* source)
: data_(new DataObjectImpl()),
source_object_(source) {
@@ -300,28 +316,7 @@
}
void OSExchangeDataProviderWin::SetFilename(const std::wstring& full_path) {
- const size_t drop_size = sizeof(DROPFILES);
- const size_t bytes = drop_size + (full_path.length() + 2) * sizeof(wchar_t);
- HANDLE hdata = ::GlobalAlloc(GMEM_MOVEABLE, bytes);
- if (!hdata)
- return;
-
- ScopedHGlobal<DROPFILES> locked_mem(hdata);
- DROPFILES* drop_files = locked_mem.get();
- drop_files->pFiles = sizeof(DROPFILES);
- drop_files->fWide = TRUE;
- wchar_t* data = reinterpret_cast<wchar_t*>((BYTE*)(drop_files) + drop_size);
- const size_t copy_size = (full_path.length() + 1) * sizeof(wchar_t);
- memcpy(data, full_path.c_str(), copy_size);
- data[full_path.length() + 1] = L'\0'; // Double NULL
-
- // Set up the STGMEDIUM
- STGMEDIUM* storage = new STGMEDIUM;
- storage->tymed = TYMED_HGLOBAL;
- storage->hGlobal = drop_files;
- storage->pUnkForRelease = NULL;
-
- // Set up the StoredDataInfo
+ STGMEDIUM* storage = GetStorageForFileName(full_path);
DataObjectImpl::StoredDataInfo* info =
new DataObjectImpl::StoredDataInfo(CF_HDROP, storage);
data_->contents_.push_back(info);
@@ -347,7 +342,7 @@
// Add CFSTR_FILECONTENTS
storage = GetStorageForBytes(file_contents.data(), file_contents.length());
data_->contents_.push_back(new DataObjectImpl::StoredDataInfo(
- ClipboardUtil::GetFileContentFormatZero()->cfFormat, storage));
+ ClipboardUtil::GetFileContentFormatZero(), storage));
}
void OSExchangeDataProviderWin::SetHtml(const std::wstring& html,
@@ -459,6 +454,21 @@
return (source_object_->QueryGetData(&format_etc) == S_OK);
}
+void OSExchangeDataProviderWin::SetDownloadFileInfo(
+ OSExchangeData::DownloadFileInfo* download) {
+ // If the filename is not provided, set stoarge to NULL to indicate that
+ // the delay rendering will be used.
+ STGMEDIUM* storage = NULL;
+ if (!download->filename.empty())
+ storage = GetStorageForFileName(download->filename.value());
+
+ // Add CF_HDROP.
+ DataObjectImpl::StoredDataInfo* info = new DataObjectImpl::StoredDataInfo(
+ ClipboardUtil::GetCFHDropFormat()->cfFormat, storage);
+ info->downloads.push_back(download);
+ data_->contents_.push_back(info);
+}
+
///////////////////////////////////////////////////////////////////////////////
// DataObjectImpl, IDataObject implementation:
@@ -533,19 +543,131 @@
destination->pUnkForRelease->AddRef();
}
-DataObjectImpl::DataObjectImpl() : ref_count_(0) {
- STLDeleteContainerPointers(contents_.begin(), contents_.end());
+DataObjectImpl::DataObjectImpl()
+ : is_aborting_(false),
+ in_async_mode_(false),
+ async_operation_started_(false),
+ observer_(NULL) {
}
DataObjectImpl::~DataObjectImpl() {
+ StopDownloads();
STLDeleteContainerPointers(contents_.begin(), contents_.end());
+ if (observer_)
+ observer_->OnDataObjectDisposed();
}
+void DataObjectImpl::StopDownloads() {
+ for (StoredData::iterator iter = contents_.begin();
+ iter != contents_.end(); ++iter) {
+ for (size_t i = 0; i < (*iter)->downloads.size(); ++i) {
+ if ((*iter)->downloads[i]->downloader) {
+ (*iter)->downloads[i]->downloader->Stop();
+ (*iter)->downloads[i]->downloader = 0;
+ }
+ delete (*iter)->downloads[i];
+ }
+ (*iter)->downloads.clear();
+ }
+}
+
+void DataObjectImpl::OnDataReady(
+ int format,
+ const std::vector<OSExchangeData::DownloadFileInfo*>& downloads) {
+ // Find and update the data corresponding to the format.
+ CLIPFORMAT clip_format = static_cast<CLIPFORMAT>(format);
+ DCHECK(clip_format == ClipboardUtil::GetCFHDropFormat()->cfFormat);
+ DataObjectImpl::StoredData::iterator iter = contents_.begin();
+ for (; iter != contents_.end(); ++iter) {
+ if ((*iter)->format_etc.cfFormat == clip_format) {
+ // Update the downloads.
+ DCHECK(downloads.size() == (*iter)->downloads.size());
+ for (size_t i = 0; i < (*iter)->downloads.size(); ++i) {
+ OSExchangeData::DownloadFileInfo* old_download = (*iter)->downloads[i];
+ (*iter)->downloads[i] = downloads[i];
+ (*iter)->downloads[i]->downloader = old_download->downloader;
+ delete old_download;
+ }
+
+ // Release the old storage.
+ if ((*iter)->owns_medium) {
+ ReleaseStgMedium((*iter)->medium);
+ delete (*iter)->medium;
+ }
+
+ // Update the storage.
+ (*iter)->owns_medium = true;
+ (*iter)->medium = GetStorageForFileName(downloads[0]->filename.value());
+
+ break;
+ }
+ }
+ DCHECK(iter != contents_.end());
+}
+
HRESULT DataObjectImpl::GetData(FORMATETC* format_etc, STGMEDIUM* medium) {
- StoredData::const_iterator iter = contents_.begin();
+ if (is_aborting_)
+ return DV_E_FORMATETC;
+
+ StoredData::iterator iter = contents_.begin();
while (iter != contents_.end()) {
- if ((*iter)->format_etc.cfFormat == format_etc->cfFormat) {
- DuplicateMedium((*iter)->format_etc.cfFormat, (*iter)->medium, medium);
+ if ((*iter)->format_etc.cfFormat == format_etc->cfFormat &&
+ (*iter)->format_etc.lindex == format_etc->lindex &&
+ ((*iter)->format_etc.tymed & format_etc->tymed)) {
+ // If medium is NULL, delay-rendering will be used.
+ if ((*iter)->medium) {
+ DuplicateMedium((*iter)->format_etc.cfFormat, (*iter)->medium, medium);
+ } else {
+ // Check if the left button is down.
+ bool is_left_button_down = (GetKeyState(VK_LBUTTON) & 0x8000) != 0;
+
+ bool wait_for_data = false;
+ if ((*iter)->in_delay_rendering) {
+ // Make sure the left button is up. Sometimes the drop target, like
+ // Shell, might be too aggresive in calling GetData when the left
+ // button is not released.
+ if (is_left_button_down)
+ return DV_E_FORMATETC;
+
+ wait_for_data = true;
+ } else {
+ // If the left button is up and the target has not requested the data
+ // yet, it probably means that the target does not support delay-
+ // rendering. So instead, we wait for the data.
+ if (is_left_button_down) {
+ (*iter)->in_delay_rendering = true;
+ memset(medium, 0, sizeof(STGMEDIUM));
+ } else {
+ wait_for_data = true;
+ }
+ }
+
+ if (wait_for_data) {
+ // Notify the observer we start waiting for the data. This gives
+ // an observer a chance to end the drag and drop.
+ if (observer_)
+ observer_->OnWaitForData();
+
+ // Now we can start the downloads. Each download will wait till the
+ // necessary data is ready and then return the control.
+ for (size_t i = 0; i < (*iter)->downloads.size(); ++i) {
+ if ((*iter)->downloads[i]->downloader) {
+ if (!(*iter)->downloads[i]->downloader->Start(
+ this, format_etc->cfFormat)) {
+ // If any of the download fails to start, abort the whole
+ // process.
+ is_aborting_ = true;
+ StopDownloads();
+ return DV_E_FORMATETC;
+ }
+ }
+ }
+
+ // The stored data should have been updated with the final version.
+ // So we just need to call this function again to retrieve it.
+ return GetData(format_etc, medium);
+ }
+ }
return S_OK;
}
++iter;
@@ -619,13 +741,46 @@
}
///////////////////////////////////////////////////////////////////////////////
+// DataObjectImpl, IAsyncOperation implementation:
+
+HRESULT DataObjectImpl::EndOperation(
+ HRESULT result, IBindCtx* reserved, DWORD effects) {
+ async_operation_started_ = false;
+ return S_OK;
+}
+
+HRESULT DataObjectImpl::GetAsyncMode(BOOL* is_op_async) {
+ *is_op_async = in_async_mode_ ? TRUE : FALSE;
+ return S_OK;
+}
+
+HRESULT DataObjectImpl::InOperation(BOOL* in_async_op) {
+ *in_async_op = async_operation_started_ ? TRUE : FALSE;
+ return S_OK;
+}
+
+HRESULT DataObjectImpl::SetAsyncMode(BOOL do_op_async) {
+ in_async_mode_ = (do_op_async == TRUE);
+ return S_OK;
+}
+
+HRESULT DataObjectImpl::StartOperation(IBindCtx* reserved) {
+ async_operation_started_ = true;
+ return S_OK;
+}
+
+///////////////////////////////////////////////////////////////////////////////
// DataObjectImpl, IUnknown implementation:
HRESULT DataObjectImpl::QueryInterface(const IID& iid, void** object) {
- *object = NULL;
- if (IsEqualIID(iid, IID_IUnknown) || IsEqualIID(iid, IID_IDataObject)) {
- *object = this;
+ if (!object)
+ return E_POINTER;
+ if (IsEqualIID(iid, IID_IDataObject) || IsEqualIID(iid, IID_IUnknown)) {
+ *object = static_cast<IDataObject*>(this);
+ } else if (in_async_mode_ && IsEqualIID(iid, IID_IAsyncOperation)) {
+ *object = static_cast<IAsyncOperation*>(this);
} else {
+ *object = NULL;
return E_NOINTERFACE;
}
AddRef();
@@ -633,16 +788,13 @@
}
ULONG DataObjectImpl::AddRef() {
- return InterlockedIncrement(&ref_count_);
+ base::RefCounted<OSExchangeData::DownloadFileObserver>::AddRef();
+ return 0;
}
ULONG DataObjectImpl::Release() {
- if (InterlockedDecrement(&ref_count_) == 0) {
- ULONG copied_refcnt = ref_count_;
- delete this;
- return copied_refcnt;
- }
- return ref_count_;
+ base::RefCounted<OSExchangeData::DownloadFileObserver>::Release();
+ return 0;
}
///////////////////////////////////////////////////////////////////////////////
@@ -721,6 +873,29 @@
*validated += extension;
}
+static STGMEDIUM* GetStorageForFileName(const std::wstring& full_path) {
+ const size_t kDropSize = sizeof(DROPFILES);
+ const size_t kTotalBytes =
+ kDropSize + (full_path.length() + 2) * sizeof(wchar_t);
+ HANDLE hdata = GlobalAlloc(GMEM_MOVEABLE, kTotalBytes);
+
+ ScopedHGlobal<DROPFILES> locked_mem(hdata);
+ DROPFILES* drop_files = locked_mem.get();
+ drop_files->pFiles = sizeof(DROPFILES);
+ drop_files->fWide = TRUE;
+ wchar_t* data = reinterpret_cast<wchar_t*>(
+ reinterpret_cast<BYTE*>(drop_files) + kDropSize);
+ const size_t copy_size = (full_path.length() + 1) * sizeof(wchar_t);
+ memcpy(data, full_path.c_str(), copy_size);
+ data[full_path.length() + 1] = L'\0'; // Double NULL
+
+ STGMEDIUM* storage = new STGMEDIUM;
+ storage->tymed = TYMED_HGLOBAL;
+ storage->hGlobal = drop_files;
+ storage->pUnkForRelease = NULL;
+ return storage;
+}
+
static STGMEDIUM* GetStorageForFileDescriptor(
const std::wstring& valid_file_name) {
DCHECK(!valid_file_name.empty() && valid_file_name.size() + 1 <= MAX_PATH);
« no previous file with comments | « app/os_exchange_data_provider_win.h ('k') | app/os_exchange_data_win_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698