diff options
Diffstat (limited to 'WebCore/platform/win/ClipboardWin.cpp')
-rw-r--r-- | WebCore/platform/win/ClipboardWin.cpp | 767 |
1 files changed, 767 insertions, 0 deletions
diff --git a/WebCore/platform/win/ClipboardWin.cpp b/WebCore/platform/win/ClipboardWin.cpp new file mode 100644 index 0000000..129d881 --- /dev/null +++ b/WebCore/platform/win/ClipboardWin.cpp @@ -0,0 +1,767 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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. + */ + +#include "config.h" +#include "ClipboardWin.h" + +#include "CString.h" +#include "CachedImage.h" +#include "ClipboardUtilitiesWin.h" +#include "Document.h" +#include "DragData.h" +#include "Editor.h" +#include "Element.h" +#include "EventHandler.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameView.h" +#include "HTMLNames.h" +#include "Image.h" +#include "MIMETypeRegistry.h" +#include "Page.h" +#include "Pasteboard.h" +#include "PlatformMouseEvent.h" +#include "PlatformString.h" +#include "Range.h" +#include "RenderImage.h" +#include "ResourceResponse.h" +#include "StringHash.h" +#include "WCDataObject.h" +#include "csshelper.h" +#include "markup.h" + +#include <shlwapi.h> +#include <wininet.h> + +#include <wtf/RefPtr.h> + +using namespace std; + +namespace WebCore { + +using namespace HTMLNames; + +// format string for +static const char szShellDotUrlTemplate[] = "[InternetShortcut]\r\nURL=%s\r\n"; + +// We provide the IE clipboard types (URL and Text), and the clipboard types specified in the WHATWG Web Applications 1.0 draft +// see http://www.whatwg.org/specs/web-apps/current-work/ Section 6.3.5.3 + +enum ClipboardDataType { ClipboardDataTypeNone, ClipboardDataTypeURL, ClipboardDataTypeText }; + +static ClipboardDataType clipboardTypeFromMIMEType(const String& type) +{ + String qType = type.stripWhiteSpace().lower(); + + // two special cases for IE compatibility + if (qType == "text" || qType == "text/plain" || qType.startsWith("text/plain;")) + return ClipboardDataTypeText; + if (qType == "url" || qType == "text/uri-list") + return ClipboardDataTypeURL; + + return ClipboardDataTypeNone; +} + +static inline FORMATETC* fileDescriptorFormat() +{ + static UINT cf = RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR); + static FORMATETC fileDescriptorFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; + return &fileDescriptorFormat; +} + +static inline FORMATETC* fileContentFormatZero() +{ + static UINT cf = RegisterClipboardFormat(CFSTR_FILECONTENTS); + static FORMATETC fileContentFormat = {cf, 0, DVASPECT_CONTENT, 0, TYMED_HGLOBAL}; + return &fileContentFormat; +} + +static inline void pathRemoveBadFSCharacters(PWSTR psz, size_t length) +{ + size_t writeTo = 0; + size_t readFrom = 0; + while (readFrom < length) { + UINT type = PathGetCharType(psz[readFrom]); + if (psz[readFrom] == 0 || type & (GCT_LFNCHAR | GCT_SHORTCHAR)) { + psz[writeTo++] = psz[readFrom]; + } + + readFrom++; + } + psz[writeTo] = 0; +} + +static String filesystemPathFromUrlOrTitle(const String& url, const String& title, TCHAR* extension, bool isLink) +{ + bool usedURL = false; + WCHAR fsPathBuffer[MAX_PATH + 1]; + fsPathBuffer[0] = 0; + int extensionLen = extension ? lstrlen(extension) : 0; + + if (!title.isEmpty()) { + size_t len = min<size_t>(title.length(), MAX_PATH - extensionLen); + CopyMemory(fsPathBuffer, title.characters(), len * sizeof(UChar)); + fsPathBuffer[len] = 0; + pathRemoveBadFSCharacters(fsPathBuffer, len); + } + + if (!lstrlen(fsPathBuffer)) { + DWORD len = MAX_PATH; + String nullTermURL = url; + usedURL = true; + if (UrlIsFileUrl((LPCWSTR)nullTermURL.charactersWithNullTermination()) + && SUCCEEDED(PathCreateFromUrl((LPCWSTR)nullTermURL.charactersWithNullTermination(), fsPathBuffer, &len, 0))) { + // When linking to a file URL we can trivially find the file name + PWSTR fn = PathFindFileName(fsPathBuffer); + if (fn && fn != fsPathBuffer) + lstrcpyn(fsPathBuffer, fn, lstrlen(fn) + 1); + } else { + // The filename for any content based drag should be the last element of + // the path. If we can't find it, or we're coming up with the name for a link + // we just use the entire url. + KURL kurl(url); + String lastComponent; + if (!isLink && !(lastComponent = kurl.lastPathComponent()).isEmpty()) { + len = min<DWORD>(MAX_PATH, lastComponent.length()); + CopyMemory(fsPathBuffer, lastComponent.characters(), len * sizeof(UChar)); + } else { + len = min<DWORD>(MAX_PATH, nullTermURL.length()); + CopyMemory(fsPathBuffer, nullTermURL.characters(), len * sizeof(UChar)); + } + fsPathBuffer[len] = 0; + pathRemoveBadFSCharacters(fsPathBuffer, len); + } + } + + if (!extension) + return String((UChar*)fsPathBuffer); + + if (!isLink && usedURL) { + PathRenameExtension(fsPathBuffer, extension); + return String((UChar*)fsPathBuffer); + } + + String result((UChar*)fsPathBuffer); + result += String((UChar*)extension); + return result; +} + +static HGLOBAL createGlobalURLContent(const String& url, int estimatedFileSize) +{ + HRESULT hr = S_OK; + HGLOBAL memObj = 0; + + char* fileContents; + char ansiUrl[INTERNET_MAX_URL_LENGTH + 1]; + // Used to generate the buffer. This is null terminated whereas the fileContents won't be. + char contentGenerationBuffer[INTERNET_MAX_URL_LENGTH + ARRAYSIZE(szShellDotUrlTemplate) + 1]; + + if (estimatedFileSize > 0 && estimatedFileSize > ARRAYSIZE(contentGenerationBuffer)) + return 0; + + int ansiUrlSize = ::WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)url.characters(), url.length(), ansiUrl, ARRAYSIZE(ansiUrl) - 1, 0, 0); + if (!ansiUrlSize) + return 0; + + ansiUrl[ansiUrlSize] = 0; + + int fileSize = (int) (ansiUrlSize+strlen(szShellDotUrlTemplate)-2); // -2 to remove the %s + ASSERT(estimatedFileSize < 0 || fileSize == estimatedFileSize); + + memObj = GlobalAlloc(GPTR, fileSize); + if (!memObj) + return 0; + + fileContents = (PSTR)GlobalLock(memObj); + + sprintf_s(contentGenerationBuffer, ARRAYSIZE(contentGenerationBuffer), szShellDotUrlTemplate, ansiUrl); + CopyMemory(fileContents, contentGenerationBuffer, fileSize); + + GlobalUnlock(memObj); + + return memObj; +} + +static HGLOBAL createGlobalImageFileContent(SharedBuffer* data) +{ + HGLOBAL memObj = GlobalAlloc(GPTR, data->size()); + if (!memObj) + return 0; + + char* fileContents = (PSTR)GlobalLock(memObj); + + CopyMemory(fileContents, data->data(), data->size()); + + GlobalUnlock(memObj); + + return memObj; +} + +static HGLOBAL createGlobalHDropContent(const KURL& url, String& fileName, SharedBuffer* data) +{ + if (fileName.isEmpty() || !data ) + return 0; + + WCHAR filePath[MAX_PATH]; + + if (url.isLocalFile()) { + String localPath = url.path(); + // windows does not enjoy a leading slash on paths + if (localPath[0] == '/') + localPath = localPath.substring(1); + LPCTSTR localPathStr = localPath.charactersWithNullTermination(); + if (wcslen(localPathStr) + 1 < MAX_PATH) + wcscpy_s(filePath, MAX_PATH, localPathStr); + else + return 0; + } else { + WCHAR tempPath[MAX_PATH]; + WCHAR extension[MAX_PATH]; + if (!::GetTempPath(ARRAYSIZE(tempPath), tempPath)) + return 0; + if (!::PathAppend(tempPath, fileName.charactersWithNullTermination())) + return 0; + LPCWSTR foundExtension = ::PathFindExtension(tempPath); + if (foundExtension) { + if (wcscpy_s(extension, MAX_PATH, foundExtension)) + return 0; + } else + *extension = 0; + ::PathRemoveExtension(tempPath); + for (int i = 1; i < 10000; i++) { + if (swprintf_s(filePath, MAX_PATH, TEXT("%s-%d%s"), tempPath, i, extension) == -1) + return 0; + if (!::PathFileExists(filePath)) + break; + } + HANDLE tempFileHandle = CreateFile(filePath, GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + if (tempFileHandle == INVALID_HANDLE_VALUE) + return 0; + + // Write the data to this temp file. + DWORD written; + BOOL tempWriteSucceeded = WriteFile(tempFileHandle, data->data(), data->size(), &written, 0); + CloseHandle(tempFileHandle); + if (!tempWriteSucceeded) + return 0; + } + + SIZE_T dropFilesSize = sizeof(DROPFILES) + (sizeof(WCHAR) * (wcslen(filePath) + 2)); + HGLOBAL memObj = GlobalAlloc(GHND | GMEM_SHARE, dropFilesSize); + if (!memObj) + return 0; + + DROPFILES* dropFiles = (DROPFILES*) GlobalLock(memObj); + dropFiles->pFiles = sizeof(DROPFILES); + dropFiles->fWide = TRUE; + wcscpy((LPWSTR)(dropFiles + 1), filePath); + GlobalUnlock(memObj); + + return memObj; +} + +static HGLOBAL createGlobalUrlFileDescriptor(const String& url, const String& title, int& /*out*/ estimatedSize) +{ + HRESULT hr = S_OK; + HGLOBAL memObj = 0; + String fsPath; + memObj = GlobalAlloc(GPTR, sizeof(FILEGROUPDESCRIPTOR)); + if (!memObj) + return 0; + + FILEGROUPDESCRIPTOR* fgd = (FILEGROUPDESCRIPTOR*)GlobalLock(memObj); + memset(fgd, 0, sizeof(FILEGROUPDESCRIPTOR)); + fgd->cItems = 1; + fgd->fgd[0].dwFlags = FD_FILESIZE; + int fileSize = ::WideCharToMultiByte(CP_ACP, 0, url.characters(), url.length(), 0, 0, 0, 0); + fileSize += strlen(szShellDotUrlTemplate) - 2; // -2 is for getting rid of %s in the template string + fgd->fgd[0].nFileSizeLow = fileSize; + estimatedSize = fileSize; + fsPath = filesystemPathFromUrlOrTitle(url, title, L".URL", true); + + if (fsPath.length() <= 0) { + GlobalUnlock(memObj); + GlobalFree(memObj); + return 0; + } + + int maxSize = min(fsPath.length(), ARRAYSIZE(fgd->fgd[0].cFileName)); + CopyMemory(fgd->fgd[0].cFileName, (LPCWSTR)fsPath.characters(), maxSize * sizeof(UChar)); + GlobalUnlock(memObj); + + return memObj; +} + + +static HGLOBAL createGlobalImageFileDescriptor(const String& url, const String& title, CachedImage* image) +{ + ASSERT_ARG(image, image); + ASSERT(image->image()->data()); + + HRESULT hr = S_OK; + HGLOBAL memObj = 0; + String fsPath; + memObj = GlobalAlloc(GPTR, sizeof(FILEGROUPDESCRIPTOR)); + if (!memObj) + return 0; + + FILEGROUPDESCRIPTOR* fgd = (FILEGROUPDESCRIPTOR*)GlobalLock(memObj); + memset(fgd, 0, sizeof(FILEGROUPDESCRIPTOR)); + fgd->cItems = 1; + fgd->fgd[0].dwFlags = FD_FILESIZE; + fgd->fgd[0].nFileSizeLow = image->image()->data()->size(); + + String extension("."); + extension += WebCore::MIMETypeRegistry::getPreferredExtensionForMIMEType(image->response().mimeType()); + const String& preferredTitle = title.isEmpty() ? image->response().suggestedFilename() : title; + fsPath = filesystemPathFromUrlOrTitle(url, preferredTitle, extension.length() ? (TCHAR*)extension.charactersWithNullTermination() : 0, false); + + if (fsPath.length() <= 0) { + GlobalUnlock(memObj); + GlobalFree(memObj); + return 0; + } + + int maxSize = min(fsPath.length(), ARRAYSIZE(fgd->fgd[0].cFileName)); + CopyMemory(fgd->fgd[0].cFileName, (LPCWSTR)fsPath.characters(), maxSize * sizeof(UChar)); + GlobalUnlock(memObj); + + return memObj; +} + + +// writeFileToDataObject takes ownership of fileDescriptor and fileContent +static HRESULT writeFileToDataObject(IDataObject* dataObject, HGLOBAL fileDescriptor, HGLOBAL fileContent, HGLOBAL hDropContent) +{ + HRESULT hr = S_OK; + FORMATETC* fe; + STGMEDIUM medium = {0}; + medium.tymed = TYMED_HGLOBAL; + + if (!fileDescriptor || !fileContent) + goto exit; + + // Descriptor + fe = fileDescriptorFormat(); + + medium.hGlobal = fileDescriptor; + + if (FAILED(hr = dataObject->SetData(fe, &medium, TRUE))) + goto exit; + + // Contents + fe = fileContentFormatZero(); + medium.hGlobal = fileContent; + if (FAILED(hr = dataObject->SetData(fe, &medium, TRUE))) + goto exit; + + // HDROP + if (hDropContent) { + medium.hGlobal = hDropContent; + hr = dataObject->SetData(cfHDropFormat(), &medium, TRUE); + } + +exit: + if (FAILED(hr)) { + if (fileDescriptor) + GlobalFree(fileDescriptor); + if (fileContent) + GlobalFree(fileContent); + if (hDropContent) + GlobalFree(hDropContent); + } + return hr; +} + +ClipboardWin::ClipboardWin(bool isForDragging, IDataObject* dataObject, ClipboardAccessPolicy policy) + : Clipboard(policy, isForDragging) + , m_dataObject(dataObject) + , m_writableDataObject(0) +{ +} + +ClipboardWin::ClipboardWin(bool isForDragging, WCDataObject* dataObject, ClipboardAccessPolicy policy) + : Clipboard(policy, isForDragging) + , m_dataObject(dataObject) + , m_writableDataObject(dataObject) +{ +} + +ClipboardWin::~ClipboardWin() +{ +} + +static bool writeURL(WCDataObject *data, const KURL& url, String title, bool withPlainText, bool withHTML) +{ + ASSERT(data); + + if (url.isEmpty()) + return false; + + if (title.isEmpty()) { + title = url.lastPathComponent(); + if (title.isEmpty()) + title = url.host(); + } + + STGMEDIUM medium = {0}; + medium.tymed = TYMED_HGLOBAL; + + medium.hGlobal = createGlobalData(url, title); + bool success = false; + if (medium.hGlobal && FAILED(data->SetData(urlWFormat(), &medium, TRUE))) + ::GlobalFree(medium.hGlobal); + else + success = true; + + if (withHTML) { + Vector<char> cfhtmlData; + markupToCF_HTML(urlToMarkup(url, title), "", cfhtmlData); + medium.hGlobal = createGlobalData(cfhtmlData); + if (medium.hGlobal && FAILED(data->SetData(htmlFormat(), &medium, TRUE))) + ::GlobalFree(medium.hGlobal); + else + success = true; + } + + if (withPlainText) { + medium.hGlobal = createGlobalData(url.string()); + if (medium.hGlobal && FAILED(data->SetData(plainTextWFormat(), &medium, TRUE))) + ::GlobalFree(medium.hGlobal); + else + success = true; + } + + return success; +} + +void ClipboardWin::clearData(const String& type) +{ + //FIXME: Need to be able to write to the system clipboard <rdar://problem/5015941> + ASSERT(isForDragging()); + if (policy() != ClipboardWritable || !m_writableDataObject) + return; + + ClipboardDataType dataType = clipboardTypeFromMIMEType(type); + + if (dataType == ClipboardDataTypeURL) { + m_writableDataObject->clearData(urlWFormat()->cfFormat); + m_writableDataObject->clearData(urlFormat()->cfFormat); + } + if (dataType == ClipboardDataTypeText) { + m_writableDataObject->clearData(plainTextFormat()->cfFormat); + m_writableDataObject->clearData(plainTextWFormat()->cfFormat); + } + +} + +void ClipboardWin::clearAllData() +{ + //FIXME: Need to be able to write to the system clipboard <rdar://problem/5015941> + ASSERT(isForDragging()); + if (policy() != ClipboardWritable) + return; + + m_writableDataObject = 0; + WCDataObject::createInstance(&m_writableDataObject); + m_dataObject = m_writableDataObject; +} + +String ClipboardWin::getData(const String& type, bool& success) const +{ + success = false; + if (policy() != ClipboardReadable || !m_dataObject) { + return ""; + } + + ClipboardDataType dataType = clipboardTypeFromMIMEType(type); + if (dataType == ClipboardDataTypeText) + return getPlainText(m_dataObject.get(), success); + else if (dataType == ClipboardDataTypeURL) + return getURL(m_dataObject.get(), success); + + return ""; +} + +bool ClipboardWin::setData(const String& type, const String& data) +{ + // FIXME: Need to be able to write to the system clipboard <rdar://problem/5015941> + ASSERT(isForDragging()); + if (policy() != ClipboardWritable || !m_writableDataObject) + return false; + + ClipboardDataType winType = clipboardTypeFromMIMEType(type); + + if (winType == ClipboardDataTypeURL) + return WebCore::writeURL(m_writableDataObject.get(), KURL(data), String(), false, true); + + if (winType == ClipboardDataTypeText) { + STGMEDIUM medium = {0}; + medium.tymed = TYMED_HGLOBAL; + medium.hGlobal = createGlobalData(data); + if (!medium.hGlobal) + return false; + + if (FAILED(m_writableDataObject->SetData(plainTextWFormat(), &medium, TRUE))) { + ::GlobalFree(medium.hGlobal); + return false; + } + return true; + } + + return false; +} + +static void addMimeTypesForFormat(HashSet<String>& results, FORMATETC& format) +{ + // URL and Text are provided for compatibility with IE's model + if (format.cfFormat == urlFormat()->cfFormat || format.cfFormat == urlWFormat()->cfFormat) { + results.add("URL"); + results.add("text/uri-list"); + } + + if (format.cfFormat == plainTextWFormat()->cfFormat || format.cfFormat == plainTextFormat()->cfFormat) { + results.add("Text"); + results.add("text/plain"); + } +} + +// extensions beyond IE's API +HashSet<String> ClipboardWin::types() const +{ + HashSet<String> results; + if (policy() != ClipboardReadable && policy() != ClipboardTypesReadable) + return results; + + if (!m_dataObject) + return results; + + COMPtr<IEnumFORMATETC> itr; + + if (FAILED(m_dataObject->EnumFormatEtc(0, &itr))) + return results; + + if (!itr) + return results; + + FORMATETC data; + + while (SUCCEEDED(itr->Next(1, &data, 0))) { + addMimeTypesForFormat(results, data); + } + + return results; +} + +void ClipboardWin::setDragImage(CachedImage* image, Node *node, const IntPoint &loc) +{ + if (policy() != ClipboardImageWritable && policy() != ClipboardWritable) + return; + + if (m_dragImage) + m_dragImage->removeClient(this); + m_dragImage = image; + if (m_dragImage) + m_dragImage->addClient(this); + + m_dragLoc = loc; + m_dragImageElement = node; +} + +void ClipboardWin::setDragImage(CachedImage* img, const IntPoint &loc) +{ + setDragImage(img, 0, loc); +} + +void ClipboardWin::setDragImageElement(Node *node, const IntPoint &loc) +{ + setDragImage(0, node, loc); +} + +DragImageRef ClipboardWin::createDragImage(IntPoint& loc) const +{ + HBITMAP result = 0; + //FIXME: Need to be able to draw element <rdar://problem/5015942> + if (m_dragImage) { + result = createDragImageFromImage(m_dragImage->image()); + loc = m_dragLoc; + } + return result; +} + +static String imageToMarkup(const String& url) +{ + String markup("<img src=\""); + markup.append(url); + markup.append("\"/>"); + return markup; +} + +static CachedImage* getCachedImage(Element* element) +{ + // Attempt to pull CachedImage from element + ASSERT(element); + RenderObject* renderer = element->renderer(); + if (!renderer || !renderer->isImage()) + return 0; + + RenderImage* image = static_cast<RenderImage*>(renderer); + if (image->cachedImage() && !image->cachedImage()->errorOccurred()) + return image->cachedImage(); + + return 0; +} + +static void writeImageToDataObject(IDataObject* dataObject, Element* element, const KURL& url) +{ + // Shove image data into a DataObject for use as a file + CachedImage* cachedImage = getCachedImage(element); + if (!cachedImage || !cachedImage->image() || !cachedImage->isLoaded()) + return; + + SharedBuffer* imageBuffer = cachedImage->image()->data(); + if (!imageBuffer || !imageBuffer->size()) + return; + + HGLOBAL imageFileDescriptor = createGlobalImageFileDescriptor(url.string(), element->getAttribute(altAttr), cachedImage); + if (!imageFileDescriptor) + return; + + HGLOBAL imageFileContent = createGlobalImageFileContent(imageBuffer); + if (!imageFileContent) { + GlobalFree(imageFileDescriptor); + return; + } + + String fileName = cachedImage->response().suggestedFilename(); + HGLOBAL hDropContent = createGlobalHDropContent(url, fileName, imageBuffer); + if (!hDropContent) { + GlobalFree(hDropContent); + return; + } + + writeFileToDataObject(dataObject, imageFileDescriptor, imageFileContent, hDropContent); +} + +void ClipboardWin::declareAndWriteDragImage(Element* element, const KURL& url, const String& title, Frame* frame) +{ + // Order is important here for Explorer's sake + if (!m_writableDataObject) + return; + WebCore::writeURL(m_writableDataObject.get(), url, title, true, false); + + writeImageToDataObject(m_writableDataObject.get(), element, url); + + AtomicString imageURL = element->getAttribute(srcAttr); + if (imageURL.isEmpty()) + return; + + String fullURL = frame->document()->completeURL(parseURL(imageURL)).string(); + if (fullURL.isEmpty()) + return; + STGMEDIUM medium = {0}; + medium.tymed = TYMED_HGLOBAL; + ExceptionCode ec = 0; + + // Put img tag on the clipboard referencing the image + Vector<char> data; + markupToCF_HTML(imageToMarkup(fullURL), "", data); + medium.hGlobal = createGlobalData(data); + if (medium.hGlobal && FAILED(m_writableDataObject->SetData(htmlFormat(), &medium, TRUE))) + ::GlobalFree(medium.hGlobal); +} + +void ClipboardWin::writeURL(const KURL& kurl, const String& titleStr, Frame*) +{ + if (!m_writableDataObject) + return; + WebCore::writeURL(m_writableDataObject.get(), kurl, titleStr, true, true); + + int estimatedSize = 0; + String url = kurl.string(); + + HGLOBAL urlFileDescriptor = createGlobalUrlFileDescriptor(url, titleStr, estimatedSize); + if (!urlFileDescriptor) + return; + HGLOBAL urlFileContent = createGlobalURLContent(url, estimatedSize); + if (!urlFileContent) { + GlobalFree(urlFileDescriptor); + return; + } + writeFileToDataObject(m_writableDataObject.get(), urlFileDescriptor, urlFileContent, 0); +} + +void ClipboardWin::writeRange(Range* selectedRange, Frame* frame) +{ + ASSERT(selectedRange); + if (!m_writableDataObject) + return; + + STGMEDIUM medium = {0}; + medium.tymed = TYMED_HGLOBAL; + ExceptionCode ec = 0; + + Vector<char> data; + markupToCF_HTML(createMarkup(selectedRange, 0, AnnotateForInterchange), + selectedRange->startContainer(ec)->document()->url().string(), data); + medium.hGlobal = createGlobalData(data); + if (medium.hGlobal && FAILED(m_writableDataObject->SetData(htmlFormat(), &medium, TRUE))) + ::GlobalFree(medium.hGlobal); + + String str = frame->selectedText(); + replaceNewlinesWithWindowsStyleNewlines(str); + replaceNBSPWithSpace(str); + medium.hGlobal = createGlobalData(str); + if (medium.hGlobal && FAILED(m_writableDataObject->SetData(plainTextWFormat(), &medium, TRUE))) + ::GlobalFree(medium.hGlobal); + + medium.hGlobal = 0; + if (frame->editor()->canSmartCopyOrDelete()) + m_writableDataObject->SetData(smartPasteFormat(), &medium, TRUE); +} + +bool ClipboardWin::hasData() +{ + if (!m_dataObject) + return false; + + COMPtr<IEnumFORMATETC> itr; + if (FAILED(m_dataObject->EnumFormatEtc(0, &itr))) + return false; + + if (!itr) + return false; + + FORMATETC data; + + if (SUCCEEDED(itr->Next(1, &data, 0))) { + // There is at least one item in the IDataObject + return true; + } + + return false; +} + +} // namespace WebCore |