📄 clipboardwin.cpp
字号:
/* * 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.3enum 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(); const String& preferredTitle = title.isEmpty() ? image->response().suggestedFilename() : title; String extension = image->image()->filenameExtension(); if (extension.isEmpty()) { // Do not continue processing in the rare and unusual case where a decoded image is not able // to provide a filename extension. Something tricky (like a bait-n-switch) is going on return 0; } extension.insert(".", 0); fsPath = filesystemPathFromUrlOrTitle(url, preferredTitle, (TCHAR*)extension.charactersWithNullTermination(), 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 fileContentstatic 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -